#include "fingerprint.h"
#include <ctype.h>

/*

The 'fingerprint' concept here is the combination of a path, its hash, the hash type, etc.

*/


void ParseBSDFormat(const char *Data, char **Type, char **Hash, char **Path)
{
    int result=FALSE;
    const char *ptr;

    ptr=GetToken(Data,"\\S",Type,0);
    if (ptr)
    {
        while (isspace(*ptr)) ptr++;
        if (*ptr=='(') ptr++;
        ptr=GetToken(ptr,")",Path,0);
        if (ptr)
        {
            while (isspace(*ptr)) ptr++;
            if (*ptr=='=') ptr++;
            while (isspace(*ptr)) ptr++;
        }
        *Hash=CopyStr(*Hash,ptr);
    }

}


void ParseTradFormat(const char *Data, char **Hash, char **Path)
{
    const char *ptr;

    ptr=GetToken(Data,"\\S",Hash,0);
    if (ptr)
    {
        if (*ptr=='*') ptr++;
        while (isspace(*ptr)) ptr++;
        *Path=CopyStr(*Path,ptr);
    }
}





void TFingerprintDestroy(void *p_Fingerprint)
{
    TFingerprint *Fingerprint;

    if (! p_Fingerprint) return;
    Fingerprint=(TFingerprint *) p_Fingerprint;
    Destroy(Fingerprint->Hash);
    Destroy(Fingerprint->Data);
    Destroy(Fingerprint->Path);
    Destroy(Fingerprint->HashType);

    free(Fingerprint);
}



TFingerprint *TFingerprintCreate(const char *Hash, const char *HashType, const char *Data, const char *Path)
{
    TFingerprint *Item;

    Item=(TFingerprint *) calloc(1,sizeof(TFingerprint));
    Item->Hash=CopyStr(Item->Hash, Hash);
    strlwr(Item->Hash);
    Item->HashType=CopyStr(Item->HashType, HashType);
    Item->Data=CopyStr(Item->Data, Data);
    Item->Path=CopyStr(Item->Path, Path);

    return(Item);
}




TFingerprint *TFingerprintParse(const char *Data)
{
    char *Name=NULL, *Value=NULL;
    const char *ptr;
    TFingerprint *FP;

    FP=(TFingerprint *) calloc(1,sizeof(TFingerprint));
    FP->Path=CopyStr(FP->Path,"");
    FP->Hash=CopyStr(FP->Hash,"");
    FP->Flags=0;
    memset(&FP->FStat,0,sizeof(struct stat));

    if (strncmp(Data,"hash=",5) ==0)
    {
//Native format

        ptr=GetNameValuePair(Data," ","=",&Name,&Value);
        while (ptr)
        {
            if (StrValid(Name))
            {
                if (strcmp(Name,"path")==0) FP->Path=UnQuoteStr(FP->Path,Value);
                if (strcmp(Name,"size")==0)
                {
                    FP->Flags |= FP_HASSTAT;
                    FP->FStat.st_size=(size_t) strtol(Value,NULL,10);
                }
                if (strcmp(Name,"mode")==0)
                {
                    FP->Flags |= FP_HASSTAT;
                    FP->FStat.st_mode=strtol(Value,NULL,8);
                }
                if (strcmp(Name,"mtime")==0)
                {
                    FP->Flags |= FP_HASSTAT;
                    FP->FStat.st_mtime=strtol(Value,NULL,10);
                }
                if (strcmp(Name,"inode")==0)
                {
                    FP->Flags |= FP_HASSTAT;
                    FP->FStat.st_ino=(ino_t) strtol(Value,NULL,10);
                }
                if (strcmp(Name,"uid")==0)
                {
                    FP->Flags |= FP_HASSTAT;
                    FP->FStat.st_uid=strtol(Value,NULL,10);
                }
                if (strcmp(Name,"gid")==0)
                {
                    FP->Flags |= FP_HASSTAT;
                    FP->FStat.st_gid=strtol(Value,NULL,10);
                }
                if (strcmp(Name,"hash")==0)
                {
                    FP->Hash=CopyStr(FP->Hash,GetToken(Value,":",&FP->HashType,0));
                }
            }
            ptr=GetNameValuePair(ptr," ","=",&Name,&Value);
        }

    }
    else
    {
        ptr=GetToken(Data," ",&FP->Hash,0);
        if (StrLen(FP->Hash) < 10) ParseBSDFormat(Data, &FP->HashType, &FP->Hash, &FP->Path);
        else ParseTradFormat(Data, &FP->Hash, &FP->Path);
    }

    if (StrValid(FP->Hash)) strlwr(FP->Hash);
    Destroy(Name);
    Destroy(Value);

    return(FP);
}


TFingerprint *FingerprintRead(STREAM *S)
{
    char *Tempstr=NULL;
    TFingerprint *FP;

    Tempstr=STREAMReadLine(Tempstr,S);
    if (! Tempstr) return(NULL);

    StripTrailingWhitespace(Tempstr);
    FP=TFingerprintParse(Tempstr);

    Destroy(Tempstr);
    return(FP);
}




int FingerprintCompare(const void *v1, const void *v2)
{
    const TFingerprint *FP1, *FP2;

    FP1=(TFingerprint *) v1;
    FP2=(TFingerprint *) v2;

    if (! FP1->Hash) return(FALSE);
    if (! FP2->Hash) return(TRUE);
    if (strcmp(FP1->Hash,FP2->Hash) < 0) return(TRUE);

    return(FALSE);
}

