#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
//platform indepent headers
#include <Platform_Lib/SubtitleParser/LRCParser.h>
#include <Platform_Lib/FontRenderer/render.h>
#include <FlowEvent.h>
#include <Util.h>

#define isnumeric(a) (((a >= '0') && (a <= '9')) ? 1 : 0)

bool LRCParser::Open(char *filename)
{
    struct stat statbuf;
    printf("==============================\n");
    if(stat(filename,&statbuf)!= 0){
        perror("no such file!\n");
        return false;
    }
    int size=statbuf.st_size;
    int fd=open(filename,O_RDONLY);
    char* file=(char*)mmap(0,size,PROT_READ,MAP_SHARED,fd,0);
    m_buf=(char*)malloc(size+1);//buffer for lrc text
    memcpy(m_buf,file,size);//GetLrcInfo needs to modify the file,so copy it into buf
    munmap(file,size);
    m_buf[size]='\0';
    m_plist=(LRC_QUEUE*)malloc(sizeof(LRC_QUEUE));
    GetLrcInfo(m_buf,size,m_plist);
    close(fd);
    m_piter=&m_plist->List[0];
    return true;
}

void LRCParser :: CopyLrcInfo(LRC_INFO *DstInfo, LRC_INFO *SrcInfo)
{
    DstInfo->Time = SrcInfo->Time;
    DstInfo->Prev = SrcInfo->Prev;
    DstInfo->Next = SrcInfo->Next;
    strcpy(DstInfo->LrcText, SrcInfo->LrcText);
}

LRC_INFO * LRCParser::GetFirstOfList(LRC_QUEUE *List)
{
    return &List->List[List->First];
}

short LRCParser::InsertList(LRC_QUEUE *List, int Time, char LrcText[])
{
    int InsertPos = -1;
    short i;
    LRC_INFO *lp = &List->List[List->Last];
    if(List->Length == 0)
    {
        List->List[0].Time = Time;
        strcpy(List->List[0].LrcText, LrcText);
        List->List[0].Prev = 0;
        List->List[0].Next = 0;
        List->First = 0;
        List->Last = 0;
        List->Length = 1;
        InsertPos = 0;
    }
    else{
        for(i = List->Length; i != 0; i--)
        {
            if(lp->Time <= Time){
                if(i == List->Length){
                    List->Last = List->Length;
                    lp->Next = &List->List[List->Length];
                    List->List[List->Length].Prev = lp;
                    List->List[List->Length].Next = 0;
                }
                else
                {
                    LRC_INFO *temp = lp->Next;
                    lp->Next = &List->List[List->Length];
                    List->List[List->Length].Prev = lp;
                    List->List[List->Length].Next = temp;
                    temp->Prev = &List->List[List->Length];
                }
                List->List[List->Length].Time = Time;
                strcpy(List->List[List->Length].LrcText, LrcText);
                InsertPos = (List->Length = List->Length + 1);
                break;
            }
            else if(i == 1){
                List->First = List->Length;
                lp->Prev = &List->List[List->Length];
                List->List[List->Length].Prev = 0;
                List->List[List->Length].Next = lp;
                List->List[List->Length].Time = Time;
                strcpy(List->List[List->Length].LrcText, LrcText);
                InsertPos = (List->Length = List->Length + 1);
            }
            lp = lp->Prev;
        }
    }
    return InsertPos;
}

int LRCParser::GetLrcInfo(char *LrcFile, int FileSize, LRC_QUEUE *List)
{
    int OffsetTime = 0;
    int CurOffset = 0;
    int CurTime = 0;
    int TempOffset;
    int Flag = 0;
    
    memset(List, 0, sizeof(*List));   
    do {
        if(LrcFile[CurOffset++] == '['){
            if(Flag == 0)
                if(strncmp(&LrcFile[CurOffset], "offset:", 7) == 0){
                    CurOffset += 7;
                    if(LrcFile[CurOffset] == '-'){
                        Flag = -1;
                        CurOffset++;
                    }
                    else
                        Flag = 1;
                    while(LrcFile[CurOffset] != ']'){
                       OffsetTime *= 10;
                       OffsetTime += LrcFile[CurOffset++] - '0';
                    }
                    OffsetTime = OffsetTime / 10 * Flag;
            }
            if(isnumeric(LrcFile[CurOffset])){
                char *lrc;
                Flag = 1;
                CurTime = (((LrcFile[CurOffset] - '0') * 10 + (LrcFile[CurOffset + 1] - '0')) * 60 +
                ((LrcFile[CurOffset + 3] - '0') * 10 + LrcFile[CurOffset + 4] - '0')) * 100;
                CurOffset += 5;
                if(LrcFile[CurOffset] == '.'){
                    CurTime += (LrcFile[CurOffset + 1] - '0') * 10 + LrcFile[CurOffset + 2] - '0';
                    CurOffset += 3;
                }
                CurOffset++;
                TempOffset = CurOffset;
                while((LrcFile[TempOffset] == '[') && isnumeric(LrcFile[TempOffset + 1])){
                    while((LrcFile[TempOffset] != ']') && (TempOffset < FileSize))
                       TempOffset++;
                    TempOffset++;
                }
                lrc = &LrcFile[TempOffset];
                while((LrcFile[TempOffset] != 0x0d) && (LrcFile[TempOffset] != 0x0a) && (TempOffset < FileSize))
                   TempOffset++;
                LrcFile[TempOffset] = '\0';
                InsertList(List, CurTime + OffsetTime, lrc);
            }
        }
    } while(CurOffset < FileSize);
    return 0;
}

bool LRCParser::Close()
{
    free(m_buf);m_buf=0;
    free(m_plist);m_plist=0;
    return true;
}

int LRCParser::GetSubtitle(int timeMs, SUBTITLE_STYLE_SHEET *stylesheet, char **text)
{  
    stylesheet->type = PLAIN;
    stylesheet->fontStyle.fontSize=20;
    int time,res;
    while(m_piter!=0){
        time=m_piter->Time*10;
        printf("%d\t",time);
        printf("%s\n",m_piter->LrcText);
        if(time>=timeMs){
            m_piter=m_piter->Prev;
            *text=m_piter->LrcText;
            res=time-timeMs;
            break;
        }
        m_piter=m_piter->Next;
    }
    if(m_piter==0)
        res=-1;
    return res;
}

int LRCParser::SubtitleSeek(int timeMs, SUBTITLE_STYLE_SHEET *stylesheet, char **text)
{
    m_piter=&m_plist->List[0];
    return GetSubtitle(timeMs,stylesheet,text);
}

