/*
 * Go2Profile.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/zGo2Profile.h>
#include <z/zGo2ProfileMeasurements.h>
#include <z/zGo2System.h>
#include <z/zGo2ProfileTypes.h>
#include <string.h>

GO2_EXPORT(Go2Status) Go2Profile_Construct(Go2Profile* profile, Go2Object system)
{
    Go2Profile output = zNIL; 
    Go2Status status = GO2_OK; 

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

    if (!zSUCCESS(status = Go2Profile_Init(output, system)))
    {
        zCHECK(Go2Object_Destroy(output)); 
        return status; 
    }
    
    *profile = output; 

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_Init(Go2Profile profile, Go2Object system)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile);

    zCHECK(Go2Object_Init(profile, GO2_TYPE_PROFILE)); 

    obj->Release = Go2Profile_VRelease; 
    obj->system = system; 

    zCHECK(Go2ProfileFeature_Construct(&obj->xAnchorFeature, system));       
    zCHECK(Go2ProfileFeature_Construct(&obj->zAnchorFeature, system)); 
    zCHECK(zList_Construct(&obj->measurements, sizeof(zHandle), 0));       

    return GO2_OK; 
}
    
GO2_EXPORT(Go2Status) Go2Profile_VRelease(Go2Profile profile)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile);
    z32u i; 

    for (i = 0; i < Go2Profile_MeasurementCount(profile); ++i)
    {
        zCHECK(Go2Object_Destroy(Go2Profile_MeasurementAt(profile, i))); 
    }

    zCHECK(Go2Object_Destroy(obj->xAnchorFeature));       
    zCHECK(Go2Object_Destroy(obj->zAnchorFeature));  
    zCHECK(zList_Destroy(obj->measurements));

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

GO2_EXPORT(Go2Status) Go2Profile_Read(Go2Profile profile, zXml xml, zXmlItem item)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    zXmlItem anchorItem = zNIL; 
    zXmlItem featureItem = zNIL; 
    zXmlItem measurementsItem = zNIL; 
    zXmlItem measurementItem = zNIL; 
    Go2Type measurementType; 
    Go2Object measurement = zNIL; 
    z32u measurementId; 
      
    zCHECK(!zIS_NIL(anchorItem = zXml_Child(xml, item, "Anchor"))); 
    
    zCHECK(zXml_Child32s(xml, anchorItem, "XEnable", &obj->xAnchorEnabled)); 
    zCHECK(!zIS_NIL(featureItem = zXml_Child(xml, anchorItem, "XFeature"))); 
    zCHECK(Go2ProfileFeature_Read(obj->xAnchorFeature, xml, featureItem));
    
    zCHECK(zXml_Child32s(xml, anchorItem, "ZEnable", &obj->zAnchorEnabled)); 
    zCHECK(!zIS_NIL(featureItem = zXml_Child(xml, anchorItem, "ZFeature"))); 
    zCHECK(Go2ProfileFeature_Read(obj->zAnchorFeature, xml, featureItem));

    zCHECK(!zIS_NIL(measurementsItem = zXml_Child(xml, item, "Measurements"))); 

    measurementItem = zXml_FirstChild(xml, measurementsItem); 

    while (!zIS_NIL(measurementItem))
    {        
        zCHECK(Go2Profile_ParseType(zXml_ItemName(xml, measurementItem), &measurementType)); 
        zCHECK(zXml_Attr32u(xml, measurementItem, "id", &measurementId)); 

        if (!zSUCCESS(Go2Profile_FindMeasurement(profile, measurementType, measurementId, &measurement)))
        {
            zCHECK(Go2Profile_CreateMeasurement(profile, measurementType, measurementId, &measurement)); 
            zCHECK(zList_Add(obj->measurements, &measurement)); 
        }

        zCHECK(Go2Measurement_Read(measurement, xml, measurementItem)); 

        measurementItem = zXml_NextSibling(xml, measurementItem); 
    }

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_Write(Go2Profile profile, zXml xml, zXmlItem item)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    zXmlItem anchorItem = zNIL; 
    zXmlItem featureItem = zNIL; 
    zXmlItem measurementsItem = zNIL; 
    zXmlItem measurementItem = zNIL; 
    Go2Object measurement = zNIL; 
    zText64 measurementName; 
    z32u i;    

    zCHECK(zXml_AddItem(xml, item, "Anchor", &anchorItem)); 

    zCHECK(zXml_SetChild32s(xml, anchorItem, "XEnable", obj->xAnchorEnabled)); 
    zCHECK(zXml_AddItem(xml, anchorItem, "XFeature", &featureItem)); 
    zCHECK(Go2ProfileFeature_Write(obj->xAnchorFeature, xml, featureItem)); 

    zCHECK(zXml_SetChild32s(xml, anchorItem, "ZEnable", obj->zAnchorEnabled)); 
    zCHECK(zXml_AddItem(xml, anchorItem, "ZFeature", &featureItem)); 
    zCHECK(Go2ProfileFeature_Write(obj->zAnchorFeature, xml, featureItem)); 
    
    zCHECK(zXml_AddItem(xml, item, "Measurements", &measurementsItem)); 
  
    for (i = 0; i < Go2Profile_MeasurementCount(profile); ++i)
    {
        Go2Object measurement = Go2Profile_MeasurementAt(profile, i); 

        zCHECK(Go2Profile_FormatType(Go2Object_Type(measurement), measurementName, zCOUNT(measurementName))); 
        
        zCHECK(zXml_AddItem(xml, measurementsItem, measurementName, &measurementItem)); 
        zCHECK(Go2Measurement_Write(measurement, xml, measurementItem)); 
    }

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_EnableXAnchor(Go2Profile profile, Go2Bool enable)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return Go2System_Set32s(obj->system,  &obj->xAnchorEnabled, enable, zFALSE, zTRUE); 
}

GO2_EXPORT(Go2Bool) Go2Profile_XAnchorEnabled(Go2Profile profile)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return obj->xAnchorEnabled;
}

GO2_EXPORT(Go2ProfileFeature) Go2Profile_XAnchorFeature(Go2Profile profile)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return obj->xAnchorFeature;
}

GO2_EXPORT(Go2Status) Go2Profile_EnableZAnchor(Go2Profile profile, Go2Bool enable)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return Go2System_Set32s(obj->system,  &obj->zAnchorEnabled, enable, zFALSE, zTRUE); 
}

GO2_EXPORT(Go2Bool) Go2Profile_ZAnchorEnabled(Go2Profile profile)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return obj->zAnchorEnabled;
}

GO2_EXPORT(Go2ProfileFeature) Go2Profile_ZAnchorFeature(Go2Profile profile)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return obj->zAnchorFeature;
}

GO2_EXPORT(Go2UInt32) Go2Profile_MeasurementCount(Go2Profile profile)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return zList_Count(obj->measurements); 
}

GO2_EXPORT(Go2Measurement) Go2Profile_MeasurementAt(Go2Profile profile, Go2UInt32 index)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    return *(Go2Object*) zList_At(obj->measurements, index); 
}

GO2_EXPORT(Go2Status) Go2Profile_CreateMeasurement(Go2Profile profile, Go2Type type, Go2UInt32 id, Go2Object* measurement)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    
    switch(type)
    {
    case GO2_TYPE_PROFILE_WIDTH:            zCHECK(Go2ProfileWidth_Construct(measurement, id, obj->system));          break;
    case GO2_TYPE_PROFILE_HEIGHT:           zCHECK(Go2ProfileHeight_Construct(measurement, id, obj->system));         break;
    case GO2_TYPE_PROFILE_DISTANCE:         zCHECK(Go2ProfileDistance_Construct(measurement, id, obj->system));       break;
    case GO2_TYPE_PROFILE_POSITION_X:       zCHECK(Go2ProfilePositionX_Construct(measurement, id, obj->system));      break;
    case GO2_TYPE_PROFILE_POSITION_Z:       zCHECK(Go2ProfilePositionZ_Construct(measurement, id, obj->system));      break;
    case GO2_TYPE_PROFILE_CENTER_X:         zCHECK(Go2ProfileCenterX_Construct(measurement, id, obj->system));        break;
    case GO2_TYPE_PROFILE_CENTER_Z:         zCHECK(Go2ProfileCenterZ_Construct(measurement, id, obj->system));        break;
    case GO2_TYPE_PROFILE_ANGLE_X:          zCHECK(Go2ProfileAngleX_Construct(measurement, id, obj->system));         break;
    case GO2_TYPE_PROFILE_ISECT_X:          zCHECK(Go2ProfileIsectX_Construct(measurement, id, obj->system));         break;
    case GO2_TYPE_PROFILE_ISECT_Z:          zCHECK(Go2ProfileIsectZ_Construct(measurement, id, obj->system));         break;
    case GO2_TYPE_PROFILE_ISECT_ANGLE:      zCHECK(Go2ProfileIsectAngle_Construct(measurement, id, obj->system));     break;
    case GO2_TYPE_PROFILE_ISECT_AREA:       zCHECK(Go2ProfileIsectArea_Construct(measurement, id, obj->system));      break;
    case GO2_TYPE_PROFILE_BOX_AREA:         zCHECK(Go2ProfileBoxArea_Construct(measurement, id, obj->system));        break;
    case GO2_TYPE_PROFILE_DIFFERENCE_AREA:  zCHECK(Go2ProfileDifferenceArea_Construct(measurement, id, obj->system)); break;
    case GO2_TYPE_PROFILE_DIFFERENCE_PEAK:  zCHECK(Go2ProfileDifferencePeak_Construct(measurement, id, obj->system)); break;
    case GO2_TYPE_PROFILE_GAP:              zCHECK(Go2ProfileGap_Construct(measurement, id, obj->system));            break;
    case GO2_TYPE_PROFILE_FLUSH:            zCHECK(Go2ProfileFlush_Construct(measurement, id, obj->system));          break;
    case GO2_TYPE_PROFILE_CIRCLE_RADIUS:    zCHECK(Go2ProfileCircleRadius_Construct(measurement, id, obj->system));   break;
    case GO2_TYPE_PROFILE_CIRCLE_X:         zCHECK(Go2ProfileCircleX_Construct(measurement, id, obj->system));        break;
    case GO2_TYPE_PROFILE_CIRCLE_Z:         zCHECK(Go2ProfileCircleZ_Construct(measurement, id, obj->system));        break;
    case GO2_TYPE_PROFILE_LINE_STD_DEV:     zCHECK(Go2ProfileLineStdDev_Construct(measurement, id, obj->system));     break;
    case GO2_TYPE_PROFILE_LINE_ERROR_MIN:   zCHECK(Go2ProfileLineErrorMin_Construct(measurement, id, obj->system));   break;
    case GO2_TYPE_PROFILE_LINE_ERROR_MAX:   zCHECK(Go2ProfileLineErrorMax_Construct(measurement, id, obj->system));   break;
    case GO2_TYPE_PROFILE_LINE_PERCENTILE:  zCHECK(Go2ProfileLinePercentile_Construct(measurement, id, obj->system)); break;
    case GO2_TYPE_PROFILE_GROOVE_X:         zCHECK(Go2ProfileGrooveX_Construct(measurement, id, obj->system));        break;
    case GO2_TYPE_PROFILE_GROOVE_Z:         zCHECK(Go2ProfileGrooveZ_Construct(measurement, id, obj->system));        break;
    case GO2_TYPE_PROFILE_GROOVE_WIDTH:     zCHECK(Go2ProfileGrooveWidth_Construct(measurement, id, obj->system));    break;
    case GO2_TYPE_PROFILE_GROOVE_DEPTH:     zCHECK(Go2ProfileGrooveDepth_Construct(measurement, id, obj->system));    break;
    case GO2_TYPE_PROFILE_BRIDGE_VALUE:     zCHECK(Go2ProfileBridgeValue_Construct(measurement, id, obj->system));    break;
    case GO2_TYPE_PROFILE_STRIP_WIDTH:      zCHECK(Go2ProfileStripWidth_Construct(measurement, id, obj->system));     break;
    case GO2_TYPE_PROFILE_STRIP_HEIGHT:     zCHECK(Go2ProfileStripHeight_Construct(measurement, id, obj->system));    break;
    case GO2_TYPE_PROFILE_STRIP_X:          zCHECK(Go2ProfileStripX_Construct(measurement, id, obj->system));         break;
    case GO2_TYPE_PROFILE_STRIP_Z:          zCHECK(Go2ProfileStripZ_Construct(measurement, id, obj->system));         break;
    case GO2_TYPE_SCRIPT:                   zCHECK(Go2Script_Construct(measurement, id, obj->system));                break;
    default:                                return GO2_ERROR_PARAMETER; 
    }
    
    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_AddMeasurement(Go2Profile profile, Go2Type type, Go2UInt32 id, Go2Measurement* measurement)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 

    zCHECK(Go2System_CheckConfigurable(obj->system)); 

    zCHECK(Go2Profile_CreateMeasurement(profile, type, id, measurement)); 
    zCHECK(zList_Add(obj->measurements, measurement)); 

    zCHECK(Go2System_SyncConfig(obj->system)); 

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_RemoveMeasurement(Go2Profile profile, Go2UInt32 index)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    Go2Measurement measurement = zNIL; 

    zCHECK(Go2System_CheckConfigurable(obj->system)); 

    zCHECK(zList_Remove(obj->measurements, index, &measurement)); 
    zCHECK(Go2Object_Destroy(measurement)); 
    
    zCHECK(Go2System_SyncConfig(obj->system)); 

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_ClearMeasurements(Go2Profile profile)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    Go2Measurement measurement = zNIL; 

    zCHECK(Go2System_CheckConfigurable(obj->system)); 

    while (zList_Count(obj->measurements) > 0)
    {
        zCHECK(zList_Remove(obj->measurements, 0, &measurement)); 
        zCHECK(Go2Object_Destroy(measurement)); 
    }
    
    zCHECK(Go2System_SyncConfig(obj->system)); 

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_FindMeasurement(Go2Profile profile, Go2Type type, Go2UInt32 id, Go2Measurement* measurement)
{
    Go2ProfileClass* obj = zHANDLE_POINTER(profile); 
    z32u i; 

    for (i = 0; i < Go2Profile_MeasurementCount(profile); ++i)
    {
        Go2Object msr = Go2Profile_MeasurementAt(profile, i); 

        if ((Go2Object_Type(msr) == type) && (Go2Measurement_Id(msr) == id))
        {
            *measurement = msr; 
            return GO2_OK; 
        }
    }

    return zERROR_NOT_FOUND; 
}

GO2_EXPORT(Go2Status) Go2Profile_ParseType(const Go2Char* typeName, Go2Type* type)
{
    if      (strcmp(typeName, "AngleX") == 0)               *type = GO2_TYPE_PROFILE_ANGLE_X;    
    else if (strcmp(typeName, "BoxArea") == 0)              *type = GO2_TYPE_PROFILE_BOX_AREA;    
    else if (strcmp(typeName, "CenterX") == 0)              *type = GO2_TYPE_PROFILE_CENTER_X;     
    else if (strcmp(typeName, "CenterZ") == 0)              *type = GO2_TYPE_PROFILE_CENTER_Z;    
    else if (strcmp(typeName, "Distance") == 0)             *type = GO2_TYPE_PROFILE_DISTANCE;
    else if (strcmp(typeName, "Height") == 0)               *type = GO2_TYPE_PROFILE_HEIGHT; 
    else if (strcmp(typeName, "IntersectAngle") == 0)       *type = GO2_TYPE_PROFILE_ISECT_ANGLE; 
    else if (strcmp(typeName, "IntersectArea") == 0)        *type = GO2_TYPE_PROFILE_ISECT_AREA; 
    else if (strcmp(typeName, "IntersectX") == 0)           *type = GO2_TYPE_PROFILE_ISECT_X; 
    else if (strcmp(typeName, "IntersectZ") == 0)           *type = GO2_TYPE_PROFILE_ISECT_Z; 
    else if (strcmp(typeName, "Width") == 0)                *type = GO2_TYPE_PROFILE_WIDTH; 
    else if (strcmp(typeName, "PositionX") == 0)            *type = GO2_TYPE_PROFILE_POSITION_X; 
    else if (strcmp(typeName, "PositionZ") == 0)            *type = GO2_TYPE_PROFILE_POSITION_Z; 
    else if (strcmp(typeName, "DifferenceArea") == 0)       *type = GO2_TYPE_PROFILE_DIFFERENCE_AREA; 
    else if (strcmp(typeName, "DifferencePeak") == 0)       *type = GO2_TYPE_PROFILE_DIFFERENCE_PEAK; 
    else if (strcmp(typeName, "Gap") == 0)                  *type = GO2_TYPE_PROFILE_GAP; 
    else if (strcmp(typeName, "Flush") == 0)                *type = GO2_TYPE_PROFILE_FLUSH; 
    else if (strcmp(typeName, "CircleRadius") == 0)         *type = GO2_TYPE_PROFILE_CIRCLE_RADIUS; 
    else if (strcmp(typeName, "CircleX") == 0)              *type = GO2_TYPE_PROFILE_CIRCLE_X; 
    else if (strcmp(typeName, "CircleZ") == 0)              *type = GO2_TYPE_PROFILE_CIRCLE_Z; 
    else if (strcmp(typeName, "LineStdDev") == 0)           *type = GO2_TYPE_PROFILE_LINE_STD_DEV; 
    else if (strcmp(typeName, "LineErrorMin") == 0)         *type = GO2_TYPE_PROFILE_LINE_ERROR_MIN; 
    else if (strcmp(typeName, "LineErrorMax") == 0)         *type = GO2_TYPE_PROFILE_LINE_ERROR_MAX; 
    else if (strcmp(typeName, "LinePercentile") == 0)       *type = GO2_TYPE_PROFILE_LINE_PERCENTILE; 
    else if (strcmp(typeName, "GrooveX") == 0)              *type = GO2_TYPE_PROFILE_GROOVE_X; 
    else if (strcmp(typeName, "GrooveZ") == 0)              *type = GO2_TYPE_PROFILE_GROOVE_Z; 
    else if (strcmp(typeName, "GrooveWidth") == 0)          *type = GO2_TYPE_PROFILE_GROOVE_WIDTH; 
    else if (strcmp(typeName, "GrooveDepth") == 0)          *type = GO2_TYPE_PROFILE_GROOVE_DEPTH; 
    else if (strcmp(typeName, "BridgeValue") == 0)          *type = GO2_TYPE_PROFILE_BRIDGE_VALUE; 
    else if (strcmp(typeName, "StripWidth") == 0)           *type = GO2_TYPE_PROFILE_STRIP_WIDTH; 
    else if (strcmp(typeName, "StripHeight") == 0)          *type = GO2_TYPE_PROFILE_STRIP_HEIGHT; 
    else if (strcmp(typeName, "StripX") == 0)               *type = GO2_TYPE_PROFILE_STRIP_X; 
    else if (strcmp(typeName, "StripZ") == 0)               *type = GO2_TYPE_PROFILE_STRIP_Z; 
    else if (strcmp(typeName, "Script") == 0)               *type = GO2_TYPE_SCRIPT; 
    else                                                    return zERROR_PARAMETER; 

    return GO2_OK; 
}

GO2_EXPORT(Go2Status) Go2Profile_FormatType(Go2Type type, Go2Char* typeName, Go2UInt32 capacity)
{
    const Go2Char* output = zNULL; 

    switch (type)
    {
        case GO2_TYPE_PROFILE_ANGLE_X:              output = "AngleX";                  break;
        case GO2_TYPE_PROFILE_BOX_AREA:             output = "BoxArea";                 break;
        case GO2_TYPE_PROFILE_CENTER_X:             output = "CenterX";                 break;
        case GO2_TYPE_PROFILE_CENTER_Z:             output = "CenterZ";                 break;
        case GO2_TYPE_PROFILE_DISTANCE:             output = "Distance";                break;
        case GO2_TYPE_PROFILE_HEIGHT:               output = "Height";                  break;
        case GO2_TYPE_PROFILE_ISECT_ANGLE:          output = "IntersectAngle";          break;
        case GO2_TYPE_PROFILE_ISECT_AREA:           output = "IntersectArea";           break;
        case GO2_TYPE_PROFILE_ISECT_X:              output = "IntersectX";              break;
        case GO2_TYPE_PROFILE_ISECT_Z:              output = "IntersectZ";              break;
        case GO2_TYPE_PROFILE_WIDTH:                output = "Width";                   break;
        case GO2_TYPE_PROFILE_POSITION_X:           output = "PositionX";               break;
        case GO2_TYPE_PROFILE_POSITION_Z:           output = "PositionZ";               break;
        case GO2_TYPE_PROFILE_DIFFERENCE_AREA:      output = "DifferenceArea";          break;
        case GO2_TYPE_PROFILE_DIFFERENCE_PEAK:      output = "DifferencePeak";          break;
        case GO2_TYPE_PROFILE_GAP:                  output = "Gap";                     break;
        case GO2_TYPE_PROFILE_FLUSH:                output = "Flush";                   break;
        case GO2_TYPE_PROFILE_CIRCLE_RADIUS:        output = "CircleRadius";            break;
        case GO2_TYPE_PROFILE_CIRCLE_X:             output = "CircleX";                 break;
        case GO2_TYPE_PROFILE_CIRCLE_Z:             output = "CircleZ";                 break;
        case GO2_TYPE_PROFILE_LINE_STD_DEV:         output = "LineStdDev";              break;
        case GO2_TYPE_PROFILE_LINE_ERROR_MIN:       output = "LineErrorMin";            break;
        case GO2_TYPE_PROFILE_LINE_ERROR_MAX:       output = "LineErrorMax";            break;
        case GO2_TYPE_PROFILE_LINE_PERCENTILE:      output = "LinePercentile";          break;
        case GO2_TYPE_PROFILE_GROOVE_X:             output = "GrooveX";                 break;
        case GO2_TYPE_PROFILE_GROOVE_Z:             output = "GrooveZ";                 break;
        case GO2_TYPE_PROFILE_GROOVE_WIDTH:         output = "GrooveWidth";             break;
        case GO2_TYPE_PROFILE_GROOVE_DEPTH:         output = "GrooveDepth";             break;
        case GO2_TYPE_PROFILE_BRIDGE_VALUE:         output = "BridgeValue";             break;
        case GO2_TYPE_PROFILE_STRIP_WIDTH:          output = "StripWidth";              break;
        case GO2_TYPE_PROFILE_STRIP_HEIGHT:         output = "StripHeight";             break;
        case GO2_TYPE_PROFILE_STRIP_X:              output = "StripX";                  break;
        case GO2_TYPE_PROFILE_STRIP_Z:              output = "StripZ";                  break;
        case GO2_TYPE_SCRIPT:                       output = "Script";                  break;
        default:                                    return zERROR_PARAMETER; 
    };
    
    strncpy(typeName, output, capacity-1);
    typeName[capacity-1] = 0; 

    return GO2_OK; 
}