/*
 * Go2Output.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/zGo2Output.h>

GO2_EXPORT(Go2Status) Go2Output_Construct(Go2Output* output, Go2Object system)
{
    Go2Output out = zNIL; 
    Go2Status status = zOK; 

    zCHECK(zCalloc(&out, 1, sizeof(Go2OutputClass))); 

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

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2Output_Init(Go2Output output, Go2Object system)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    z32u i; 
    zXmlItem tempItem;

    zCHECK(Go2Object_Init(output, GO2_TYPE_OUTPUT)); 

    obj->Release = Go2Output_VRelease; 
    obj->system = system; 

    zCHECK(Go2Ethernet_Construct(&obj->ethernet, system)); 
    zCHECK(Go2Serial_Construct(&obj->serial, system)); 
    zCHECK(Go2Analog_Construct(&obj->analog, system)); 

    for (i = 0; i < zCOUNT(obj->digital); ++i)
    {
        zCHECK(Go2Digital_Construct(&obj->digital[i], i, system)); 
    }

    zCHECK(zXml_Construct(&obj->custom));
    zCHECK(zXml_AddItem(obj->custom, zNIL, "Custom", &tempItem));

    return zOK; 
}
    
GO2_EXPORT(Go2Status) Go2Output_VRelease(Go2Output output)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    z32u i;

    zCHECK(Go2Object_Destroy(obj->ethernet)); 
    zCHECK(Go2Object_Destroy(obj->serial)); 
    zCHECK(Go2Object_Destroy(obj->analog)); 

    for (i = 0; i < zCOUNT(obj->digital); ++i)
    {
        zCHECK(Go2Object_Destroy(obj->digital[i])); 
    }

    zCHECK(zXml_Destroy(obj->custom));
    zCHECK(Go2Object_VRelease(output));  
        
    return zOK; 
}

GO2_EXPORT(Go2Status) Go2Output_Read(Go2Output output, zXml xml, zXmlItem item)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    zXmlItem ethernetItem = zNIL; 
    zXmlItem serialItem = zNIL; 
    zXmlItem digitalItem = zNIL; 
    zXmlItem analogItem = zNIL; 
    zXmlItem customItem = zNIL;
    zXmlItem tempItem = zNIL;
    z32u i; 
    
    zCHECK(!zIS_NIL(ethernetItem = zXml_Child(xml, item, "Ethernet"))); 
    zCHECK(Go2Ethernet_Read(obj->ethernet, xml, ethernetItem)); 
    
    zCHECK(!zIS_NIL(serialItem = zXml_Child(xml, item, "Serial"))); 
    zCHECK(Go2Serial_Read(obj->serial, xml, serialItem)); 

    zCHECK(!zIS_NIL(analogItem = zXml_Child(xml, item, "Analog"))); 
    zCHECK(Go2Analog_Read(obj->analog, xml, analogItem)); 

    digitalItem = zXml_Child(xml, item, "DigitalOutput"); 

    for (i = 0; i < zCOUNT(obj->digital); ++i)
    {
        zCHECK(!zIS_NIL(digitalItem)); 
        zCHECK(Go2Digital_Read(obj->digital[i], xml, digitalItem)); 
        
        digitalItem = zXml_NextSibling(xml, digitalItem); 
    }

    zCHECK(zXml_Clear(obj->custom));
    customItem = zXml_Child(xml, item, "Custom"); 

    if (!zIS_NIL(customItem))
    {
        zCHECK(zXml_CopyItem(obj->custom, zNIL, zNIL, xml, customItem, &tempItem));
    }

    return zOK; 
}

GO2_EXPORT(Go2Status) Go2Output_Write(Go2Output output, zXml xml, zXmlItem item)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    zXmlItem ethernetItem = zNIL; 
    zXmlItem serialItem = zNIL; 
    zXmlItem digitalItem = zNIL; 
    zXmlItem analogItem = zNIL; 
    zXmlItem customItem = zNIL;
    z32u i; 
    
    zCHECK(zXml_AddItem(xml, item, "Ethernet", &ethernetItem)); 
    zCHECK(Go2Ethernet_Write(obj->ethernet, xml, ethernetItem)); 

    zCHECK(zXml_AddItem(xml, item, "Serial", &serialItem)); 
    zCHECK(Go2Serial_Write(obj->serial, xml, serialItem)); 

    zCHECK(zXml_AddItem(xml, item, "Analog", &analogItem)); 
    zCHECK(Go2Analog_Write(obj->analog, xml, analogItem)); 

    for (i = 0; i < zCOUNT(obj->digital); ++i)
    {
        zCHECK(zXml_AddItem(xml, item, "DigitalOutput", &digitalItem)); 
        zCHECK(Go2Digital_Write(obj->digital[i], xml, digitalItem)); 
    }
        
    //custom config for output element
    zCHECK(zXml_CopyItem(xml, item, zNIL, obj->custom, zXml_Root(obj->custom), &customItem));

    return zOK; 
}

GO2_EXPORT(Go2Ethernet) Go2Output_Ethernet(Go2Output output)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    return obj->ethernet; 
}

GO2_EXPORT(Go2Serial) Go2Output_Serial(Go2Output output)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    return obj->serial; 
}

GO2_EXPORT(Go2UInt32) Go2Output_DigitalCount(Go2Output output)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    return zCOUNT(obj->digital); 
}

GO2_EXPORT(Go2Digital) Go2Output_DigitalAt(Go2Output output, Go2UInt32 index)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    return obj->digital[index]; 
}

GO2_EXPORT(Go2Analog) Go2Output_Analog(Go2Output output)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);
    return obj->analog; 
}

GO2_EXPORT(zXml) Go2Output_CustomElement(Go2Output output)
{
    Go2OutputClass* obj = zHANDLE_POINTER(output);

    return obj->custom;
}
