#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "list.h"
#include "av_ringbuffer.h"
#include "iot_math.h"


/*
 * 不用移动rb->read指针, 只是复制出来
 * 尽可能减少数据的复制, 如只为了判断类型时只要复制结构体
 */
static int32_t av_ringbuffer_get_frame_locked(ringbuffer *rb, ring_item *item, void *to, int8_t size){
	const int32_t end_pos = (item->pos + size) - (rb->buffer + rb->capacity);
	if (end_pos <= 0){
		memcpy(to, item->pos, size);
	}else{
		memcpy(to, item->pos, size - end_pos);
		memcpy(to + size - end_pos, rb->buffer, end_pos);
	}
}

#if 0
uint32_t av_ringbuffer_get_video_frame(ringbuffer *rb, av_cookie *cookie, video_frame *to, uint32_t max_len, uint32_t timeout){
	int32_t ret = NG;
    ring_item *item = NULL;
	hmutex_lock(&rb->mutex);
	if (!list_empty(&rb->list[RING_LIST_USING])){
        if (cookie->item && /* 正常情况直接获取下一个帧, 否则进入后面的异常情况去搜索 */
            (cookie->item->seq > rb->last_drop_seq || rb->last_drop_seq == UINT32_MAX) && cookie->item->seq < ringbuffer_get_lastseq_locked(rb)) {/* 直接获取下一个*/
                 item = list_entry(cookie->item->link.next, ring_item, link);   
        }else if (cookie->dir == LATEST_IFRAME){/*直播查找最新的关键帧*/
            struct list_head *pos, *n;
            list_for_each_prev_safe(pos, n, &rb->list[RING_LIST_USING])
            {
                ring_item* tmp_item = list_entry(pos, ring_item, link);
                av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(video_frame));
                if((to->type & FRAME_TYPE_IFRAME) && (!cookie->item || tmp_item->seq >= cookie->item->seq)){
                    item = tmp_item;
                    break;
                }
			}
		}else{/* dir = NEXT_IFRAME 查找比cookie->item新的关键帧, 如oss, 又不想丢太多 */
		    struct list_head *pos, *n;
            list_for_each_safe(pos, n, &rb->list[RING_LIST_USING])
            {
                ring_item* tmp_item = list_entry(pos, ring_item, link);
                av_ringbuffer_get_frame_locked(rb, tmp_item, to, sizeof(video_frame));
                if((to->type & FRAME_TYPE_IFRAME) && (!cookie->item || tmp_item->seq >= cookie->item->seq) /*&& (to->ts >= cookie->startPTS)*/) {/*头一个, 或者 下一个*/
                    item = tmp_item;
                    break;
                }
            }
		}
	}
	hmutex_unlock(&rb->mutex);
    if ( item ) {
        cookie->item = item;
        av_ringbuffer_get_frame_locked(rb, item, to, sizeof(video_frame) + item->size);
        //hlogd("av_ringbuffer_get_video_frame %u %X %u\n", cookie->item->seq, rb->last_drop_seq, ringbuffer_get_lastseq_locked(rb)); 
        ret = OK;
    } else {
        ret = NG; 
        if (timeout) {
            if ( hsem_wait_for(&rb->sem, timeout) ){ /* 没有数据,调用端再重新call */
                /* 正常, 收到了sem, 有新的av帧送入 */
            } else {
                /* 超时没收到 sem */
            }
        }
        
    }
    return ret;
}

#endif
#if 1

void av_ringbuffer_test()
{
	hlogi("test_av_ringbuffer\n");
    #define TEST_CNT (10)
	av_ringbuffer *v_ring = av_ringbuffer_init(3*1024*1024);
	int i;
	for(i=0;i<TEST_CNT;i++){
		video_frame *vframe = avframe_create(video_frame, i+10);
		vframe->chn = 0;
        vframe->type = i % 15 == 0 ? FRAME_TYPE_IFRAME : FRAME_TYPE_PBFRAME;
		vframe->format = VIDEO_FORMAT_H264;
		vframe->seq = i;
        sprintf(vframe->data, "im %d", i);
		if (!av_ringbuffer_put(v_ring, vframe, vframe->data)){
			hlogi("av_ringbuffer_put err:%u read:%p\n", vframe->size);
		}
		free(vframe);
	}
	hlogi("av_ringbuffer_put\n");
    av_ringbuffer_dump(v_ring);
    av_cookie cookie = {0};
    cookie.dir = NEXT_IFRAME;
    av_cookie *pcookie = &cookie;
	video_frame *vframe = (video_frame*)calloc(1, sizeof(video_frame)+MAX_VFRAME_SIZE);
	for(i=0;i<TEST_CNT;i++){
		if (OK == av_ringbuffer_get_frame(v_ring, pcookie, vframe, i+10, 1000)){
			hlogi("1 av_ringbuffer_get_video_frame i:%d seq:%u, size:%u cookie->item->seq:%u data:%s\n", i, vframe->seq, vframe->size, cookie.item->seq, vframe->data);
		}else{
			hlogi("1 av_ringbuffer_get_video_frame err:%d\n", i);
			//break;
		}
	}
	free(vframe);
    hlogi("test_av_ringbuffer end\n");
}

#endif

