/*
 * Go2Data.h
 * 
 * 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/zGo2Data.h>
#include <z/zGo2DataTypes.h>

GO2_EXPORT(Go2Status) Go2Data_Construct(Go2Data* data, zResult result)
{
    Go2Data output = zNIL; 
    Go2Status status = zOK; 

    zCHECK(zCalloc(&output, 1, sizeof(Go2DataClass))); 

    if (!zSUCCESS(status = Go2Data_Init(output, result)))
    {
        zCHECK(Go2Object_Destroy(output)); 
        return status; 
    }
    
    *data = output; 

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Data_Destroy(Go2Data data)
{
    return Go2Object_Destroy(data); 
}

GO2_EXPORT(Go2Status) Go2Data_Init(Go2Data data, zResult result)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    z32u attributeCount = zResult_AttributeCount(result);
    z32u itemCount = zResult_ItemCount(result); 
    z32u groupItemCount = GO2_DATA_ITEMS_PER_RESULT_BLOCK; 
    z32u groupCount = itemCount / groupItemCount; 
    z32u i; 

    zCHECK(Go2Object_Init(data, GO2_TYPE_DATA)); 

    obj->Release = Go2Data_VRelease; 

    zCHECK(zResult_Id(result) == GO2_DATA_MESSAGE_ID); 
    zCHECK(attributeCount >= GO2_DATA_ATTRIBUTE_COUNT);     
    zCHECK((itemCount % GO2_DATA_ITEMS_PER_RESULT_BLOCK) == 0); 

    zCHECK(zList_Construct(&obj->items, sizeof(zHandle), 0)); 
    
    for (i = 0; i < groupCount; ++i)
    {
        z32u groupOffset = i*groupItemCount; 
        const z64s* itemAttributes = zResult_ItemData(result, groupOffset);       
        Go2Object item = GO2_NIL;
        
        switch (itemAttributes[GO2_DATA_CONTENT_ATTRIBUTE_TYPE])
        {
        case GO2_DATA_CONTENT_TYPE_VIDEO:                   zCHECK(Go2VideoData_Construct(&item, result, groupOffset, groupOffset+1));          break;
        case GO2_DATA_CONTENT_TYPE_RANGE:                   zCHECK(Go2RangeData_Construct(&item, result, groupOffset, groupOffset+1));          break;
        case GO2_DATA_CONTENT_TYPE_PROFILE:                 zCHECK(Go2ProfileData_Construct(&item, result, groupOffset, groupOffset+1));        break;
        case GO2_DATA_CONTENT_TYPE_PART:                    zCHECK(Go2PartData_Construct(&item, result, groupOffset, groupOffset+1));           break;
        case GO2_DATA_CONTENT_TYPE_RAW_PROFILE:             zCHECK(Go2RawProfileData_Construct(&item, result, groupOffset, groupOffset+1));     break;
        case GO2_DATA_CONTENT_TYPE_ALIGNMENT:               zCHECK(Go2AlignmentData_Construct(&item, result, groupOffset, groupOffset+1));      break;
        case GO2_DATA_CONTENT_TYPE_TRAVEL:                  zCHECK(Go2TravelData_Construct(&item, result, groupOffset, groupOffset+1));         break;
        case GO2_DATA_CONTENT_TYPE_EXPOSURE:                zCHECK(Go2ExposureData_Construct(&item, result, groupOffset, groupOffset+1));       break;
        case GO2_DATA_CONTENT_TYPE_REFERENCE_IMAGE:         zCHECK(Go2ReferenceImageData_Construct(&item, result, groupOffset, groupOffset+1));       break;
        case GO2_DATA_CONTENT_TYPE_MEASUREMENT_A:
        case GO2_DATA_CONTENT_TYPE_MEASUREMENT_B:
        case GO2_DATA_CONTENT_TYPE_MEASUREMENT_C:
        case GO2_DATA_CONTENT_TYPE_MEASUREMENT_D:
        case GO2_DATA_CONTENT_TYPE_MEASUREMENT_E:           zCHECK(Go2MeasurementData_Construct(&item, result, groupOffset, groupOffset+1));            break;
        case GO2_DATA_CONTENT_TYPE_RANGE_INTENSITY:         zCHECK(Go2RangeIntensityData_Construct(&item, result, groupOffset, groupOffset+1));         break;
        case GO2_DATA_CONTENT_TYPE_PROFILE_INTENSITY:       zCHECK(Go2ProfileIntensityData_Construct(&item, result, groupOffset, groupOffset+1));       break;
        case GO2_DATA_CONTENT_TYPE_RAW_PROFILE_INTENSITY:   zCHECK(Go2RawProfileIntensityData_Construct(&item, result, groupOffset, groupOffset+1));    break;
        case GO2_DATA_CONTENT_TYPE_PART_INTENSITY:          zCHECK(Go2PartIntensityData_Construct(&item, result, groupOffset, groupOffset+1));          break;
        case GO2_DATA_CONTENT_TYPE_PROFILE_TEMPLATE:        zCHECK(Go2ProfileTemplateData_Construct(&item, result, groupOffset, groupOffset+1));        break;
        default:  
            if (itemAttributes[GO2_DATA_CONTENT_ATTRIBUTE_TYPE] >= GO2_DATA_CONTENT_TYPE_CUSTOM)
            {
                zCHECK(Go2CustomData_Construct(&item, 
                                                result, 
                                                groupOffset, 
                                                groupOffset+1, 
                                                (z32u) itemAttributes[GO2_DATA_CONTENT_ATTRIBUTE_TYPE]));
            }
            else
            {
                return zERROR;
            } break;
        }

        zCHECK(zList_Add(obj->items, &item)); 
    }

    obj->result = result; 

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Data_VRelease(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    Go2Object item = GO2_NIL;
    z32u i;

    if (!zIS_NIL(obj->items))
    {
        for (i = 0; i < zList_Count(obj->items); ++i)
        {
            zCHECK(zList_Item(obj->items, i, &item)); 
            zCHECK(Go2Object_Destroy(item)); 
        }

        zCHECK(zList_Destroy(obj->items)); 
    }

    zCHECK(zResult_Destroy(obj->result)); 

    zCHECK(Go2Object_VRelease(data));  
        
    return GO2_OK; 
}

GO2_EXPORT(Go2UInt64) Go2Data_Timestamp(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    return (Go2UInt64) zResult_AttributeAt(obj->result, GO2_DATA_ATTRIBUTE_TIMESTAMP); 
}

GO2_EXPORT(Go2Int64) Go2Data_Encoder(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    return zResult_AttributeAt(obj->result, GO2_DATA_ATTRIBUTE_ENCODER); 
}

GO2_EXPORT(Go2Int64) Go2Data_EncoderIndexValue(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    return zResult_AttributeAt(obj->result, GO2_DATA_ATTRIBUTE_ENCODER_INDEX_VALUE); 
}

GO2_EXPORT(Go2UInt64) Go2Data_Inputs(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    return zResult_AttributeAt(obj->result, GO2_DATA_ATTRIBUTE_DIGITAL_INPUTS); 
}

GO2_EXPORT(Go2UInt64) Go2Data_FrameIndex(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    return (Go2UInt64) zResult_AttributeAt(obj->result, GO2_DATA_ATTRIBUTE_FRAME_INDEX); 
}

GO2_EXPORT(Go2UInt32) Go2Data_ItemCount(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    return zList_Count(obj->items); 
}

GO2_EXPORT(Go2Object) Go2Data_ItemAt(Go2Data data, Go2UInt32 index)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    Go2Object item = zNIL; 

    return zSUCCESS(zList_Item(obj->items, index, &item)) ? item : zNIL; 
}

GO2_EXPORT(zResult) Go2Data_Result(Go2Data data)
{
    Go2DataClass* obj = zHANDLE_POINTER(data);
    return obj->result; 
}

