/*
 * Go2Api.c
 * 
 * Gocator system communication library
 * Copyright (C) 2010 by LMI Technologies Inc.
 * 
 * Licensed under The MIT License.
 * Redistributions of files must retain the above copyright notice.
 */
#include <z/zGo2Api.h>
#include <zApi.h>
#include <zNetwork.h>
#include <string.h>
#include <stdio.h>

GO2_EXPORT(Go2Status) Go2Api_Initialize()
{
    return zApi_Initialize(); 
}

GO2_EXPORT(Go2Status) Go2Api_Terminate()
{
    return zApi_Terminate(); 
}

GO2_EXPORT(Go2UInt32) Go2Api_Version()
{
    return zVersion_Create(GOCATOR_VERSION_MAJOR, GOCATOR_VERSION_MINOR, GOCATOR_VERSION_RELEASE, GOCATOR_VERSION_BUILD); 
}

GO2_EXPORT(Go2Version) Go2Version_Create(Go2UInt32 major, Go2UInt32 minor, Go2UInt32 release, Go2UInt32 build)
{
    return zVersion_Create(major, minor, release, build); 
}

GO2_EXPORT(Go2UInt8) Go2Version_Major(Go2Version version)
{
    return zVersion_Major(version); 
}

GO2_EXPORT(Go2UInt8) Go2Version_Minor(Go2Version version)
{
    return zVersion_Minor(version); 
}

GO2_EXPORT(Go2UInt8) Go2Version_Release(Go2Version version)
{
    return zVersion_Release(version); 
}

GO2_EXPORT(Go2UInt8) Go2Version_Build(Go2Version version)
{
    return zVersion_Build(version); 
}

GO2_EXPORT(Go2Status) Go2Free(void* memory)
{
    return zFree(memory); 
}

GO2_EXPORT(Go2Status) Go2Destroy(Go2Object* object)
{
    if (!zIS_NULL(object))
    {
        zCHECK(Go2Object_Destroy(*object)); 
        *object = zNIL; 
    }

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2IPAddress_Parse(const Go2Char* text, Go2IPAddress* address)
{
    return zIPAddress_Parse(text, address); 
}

GO2_EXPORT(Go2Status) Go2IPAddress_Format(Go2IPAddress address, Go2Char* text, Go2UInt32 capacity)
{
    return zIPAddress_Format(address, text, capacity); 
}

GO2_EXPORT(Go2Status) Go2Mode_Parse(const Go2Char* text, Go2Mode* mode)
{    
    if      (strcmp(text, "Video") == 0)                *mode = GO2_MODE_VIDEO;    
    else if (strcmp(text, "RangeMeasure") == 0)         *mode = GO2_MODE_RANGE_MEASUREMENT;  
    else if (strcmp(text, "ProfileTemplate") == 0)      *mode = GO2_MODE_PROFILE_TEMPLATE;    
    else if (strcmp(text, "PartTemplate") == 0)         *mode = GO2_MODE_PART_TEMPLATE;  
    else if (strcmp(text, "ProfileMeasure") == 0)       *mode = GO2_MODE_PROFILE_MEASUREMENT; 
    else if (strcmp(text, "PartMeasure") == 0)          *mode = GO2_MODE_PART_MEASUREMENT; 
    else if (strcmp(text, "Raw") == 0)                  *mode = GO2_MODE_RAW_PROFILE;    
    else if (strcmp(text, "ExpCalibrate") == 0)         *mode = GO2_MODE_EXPOSURE_CAL;
    else if (strcmp(text, "AlignCalibrate") == 0)       *mode = GO2_MODE_ALIGN_CAL; 
    else if (strcmp(text, "TravelCalibrate") == 0)      *mode = GO2_MODE_TRAVEL_CAL;
    else if (strcmp(text, "ReferenceImage") == 0)       *mode = GO2_MODE_REFERENCE_IMAGE; 
    else if (strcmp(text, "Roline") == 0)               *mode = GO2_MODE_ROLINE; 
    else 
    {
        *mode = GO2_MODE_CUSTOM;                                               
        strcpy(GO2_CUSTOM_MODE_STRING, text);
    }
    
    return zOK; 
}

GO2_EXPORT(Go2Status) Go2Mode_Format(Go2Mode mode, Go2Char* text, Go2UInt32 capacity)
{
    const Go2Char* output = zNULL; 

    switch (mode)
    {
        case GO2_MODE_VIDEO:                   output = "Video";                 break;
        case GO2_MODE_RANGE_MEASUREMENT:       output = "RangeMeasure";       break;
        case GO2_MODE_PROFILE_TEMPLATE:        output = "ProfileTemplate";       break;
        case GO2_MODE_PART_TEMPLATE:           output = "PartTemplate";          break;
        case GO2_MODE_PROFILE_MEASUREMENT:     output = "ProfileMeasure";        break;
        case GO2_MODE_PART_MEASUREMENT:        output = "PartMeasure";           break;
        case GO2_MODE_RAW_PROFILE:             output = "Raw";                   break;
        case GO2_MODE_EXPOSURE_CAL:            output = "ExpCalibrate";          break;
        case GO2_MODE_ALIGN_CAL:               output = "AlignCalibrate";        break;
        case GO2_MODE_TRAVEL_CAL:              output = "TravelCalibrate";       break;
        case GO2_MODE_REFERENCE_IMAGE:         output = "ReferenceImage";       break;
        case GO2_MODE_ROLINE:                  output = "Roline";                break;
        case GO2_MODE_CUSTOM:                  output = GO2_CUSTOM_MODE_STRING; break;
        default:                               return GO2_ERROR_PARAMETER; 
    };
    
    strncpy(text, output, capacity-1);
    text[capacity-1] = 0; 

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2SensorModel_Parse(const Go2Char* text, z32u* model)
{    
    if (sscanf(text, "Gocator_%u", model) != 1)
    {
        return zERROR_PARAMETER; 
    }

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2SensorModel_Format(z32u model, Go2Char* text, Go2UInt32 capacity)
{
    zText64 buffer; 

    sprintf(buffer, "Gocator_%u", model); 
    
    strncpy(text, buffer, capacity); 
    buffer[capacity-1] = 0; 

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2OptionList_ParseHelper(const zChar* text, zUIntPtr length, z32u* value)
{
    zText64 buffer; 

    zCHECK(length  < zCOUNT(buffer)); 

    strncpy(buffer, text, length); 
    buffer[length] = 0; 

    zCHECK(sscanf(buffer, "%u", value) == 1); 

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2OptionList_ParseHelperText(const zChar* text, zUIntPtr length, zChar* value, z32u capacity)
{
    zCHECK(length < capacity); 

    strncpy(value, text, length); 
    value[length] = 0; 

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2OptionList_ParseList(const zChar* text, zList list)
{
    z32u outCount  = 0; 
    const zChar* readIt = text; 
    const zChar* separator = zNULL; 
    z32u option = 0; 

    zCHECK(zList_Alloc(list, sizeof(z32u), 0)); 

    while (!zIS_NULL(separator = strchr(readIt, ',')))
    {
        if (zSUCCESS(Go2OptionList_ParseHelper(readIt, separator - readIt, &option)))
        {
            zCHECK(zList_Add(list, &option)); 
        }
        readIt = separator + 1; 
    }
    if (zSUCCESS(Go2OptionList_ParseHelper(readIt, strlen(readIt), &option)))
    {
        zCHECK(zList_Add(list, &option)); 
    }
  
    return zOK;    
}

GO2_EXPORT(Go2Status) Go2OptionList_ParseListText64(const zChar* text, zList list)
{
    z32u outCount  = 0; 
    const zChar* readIt = text; 
    const zChar* separator = zNULL; 
    zText64 option; 

    zCHECK(zList_Alloc(list, sizeof(zText64), 0)); 

    while (!zIS_NULL(separator = strchr(readIt, ',')))
    {
        if (zSUCCESS(Go2OptionList_ParseHelperText(readIt, separator - readIt, option, GO2_COUNT(option))))
        {
            zCHECK(zList_Add(list, &option)); 
        }
        readIt = separator + 1; 
    }
    if (zSUCCESS(Go2OptionList_ParseHelperText(readIt, strlen(readIt), option, GO2_COUNT(option))))
    {
        zCHECK(zList_Add(list, &option)); 
    }
    

    return zOK;    
}

GO2_EXPORT(Go2Status) Go2OptionList_Parse(const zChar* text, z32u* optionList, z32u capacity, z32u* count)
{
    zList list = zNIL; 

    zEXCEPT_TRY
    {
        zEXCEPT_CHECK(zList_Construct(&list, sizeof(z32u), capacity)); 
        zEXCEPT_CHECK(Go2OptionList_ParseList(text, list)); 

        *count = zMATH_MIN(capacity, zList_Count(list)); 
        memcpy(optionList, zList_Data(list), (*count) * sizeof(z32u)); 
    }
    zEXCEPT_CATCH(zNULL) {}
    zEXCEPT_FINALLY
    {
        zEXCEPT_SET(zList_Destroy(list)); 
        zEXCEPT_CLOSE(); 
    }

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2OptionList_Format(const z32u* optionList, z32u count, zChar* text, z32u capacity)
{
    zText64 buffer; 
    z32u totalLength = 0; 
    z32u length = 0; 
    z32u i; 
    
    text[0] = 0; 

    for (i = 0; i < count; ++i)
    {
        length = sprintf(buffer, "%s%u", (i != 0) ? "," : "", optionList[i]);         

        if ((totalLength + length) < capacity)
        {
            strcpy(&text[totalLength], buffer); 
            totalLength += length; 
        }
        else
        {
            return zERROR_PARAMETER; 
        }
    }
    
    return zOK; 
}


GO2_EXPORT(Go2Status) Go2OptionList_FormatText64(const zText64* optionList, z32u count, zChar* text, z32u capacity)
{
    zText64 buffer; 
    z32u totalLength = 0; 
    z32u length = 0; 
    z32u i; 

    text[0] = 0; 

    for (i = 0; i < count; ++i)
    {
        length = sprintf(buffer, "%s%s", (i != 0) ? "," : "", optionList[i]);         

        if ((totalLength + length) < capacity)
        {
            strcpy(&text[totalLength], buffer); 
            totalLength += length; 
        }
        else
        {
            return zERROR_PARAMETER; 
        }
    }

    return zOK; 
}