// $Id: JGVariable.cpp,v 1.4 2003/03/16 14:51:01 fukasawa Exp $

//=============================================================================
/**
 *  @file    JGVariable.cpp
 *
 *  @author  Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 2001-2003 BEE Co.,Ltd. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
//=============================================================================

#define BEE_BUILD_DLL

#include "JGVariable.h"
#include "JGTriggerInfo.h"
#include "sac/JGIODevice.h"
#include "BS2Atom.h"
#include "BS2Item.h"
#include "BS2ListItem.h"
#include "BS2Ascii.h"

static bool type_compare(int dType, int vType, int aType)
{
    int ft1 = dType, ft2 = vType;
    if (aType < 0)
    {
        if (dType == ATOM_INT1 || dType == ATOM_INT2 || dType == ATOM_INT4)
        {
            ft1 = ATOM_INT4;
        }
        else if (dType == ATOM_UINT1 || dType == ATOM_UINT2 ||
                 dType == ATOM_UINT4)
        {
            ft1 = ATOM_UINT4;
        }
        if (vType == ATOM_INT1 || vType == ATOM_INT2 || vType == ATOM_INT4)
        {
            ft2 = ATOM_INT4;
        }
        else if (vType == ATOM_UINT1 || vType == ATOM_UINT2 ||
                 vType == ATOM_UINT4)
        {
            ft2 = ATOM_UINT4;
        }
    }
    else
    {
        ft2 = aType;
    }
    return (ft1 == ft2);
}

//-----------------------------------------------------------------------------
// Copy
//-----------------------------------------------------------------------------
JGVariable& JGVariable::operator=(const JGVariable& rhs)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::operator=");
    if (this == &rhs)
        return *this;
    this->copy(rhs);
    return *this;
}

//-----------------------------------------------------------------------------
void JGVariable::copy(const JGVariable& rhs)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::copy");

    this->JGNameInfo::copy(rhs);
    m_ecsvid  = rhs.m_ecsvid;
    m_class   = rhs.m_class;
    m_valtype = rhs.m_valtype;
    m_size    = rhs.m_size;
    m_value   = rhs.m_value;
    m_unit    = rhs.m_unit;
    m_itemname = rhs.m_itemname;
    m_func    = rhs.m_func;
    m_trgid   = rhs.m_trgid;
    m_offset  = rhs.m_offset;
    m_limitEnabled = rhs.m_limitEnabled;
    m_enabled = rhs.m_enabled;
    m_save    = rhs.m_save;
    m_hostupd = rhs.m_hostupd;
    m_iodev   = rhs.m_iodev;
    m_initval = rhs.m_initval;
    m_minval  = rhs.m_minval;
    m_maxval  = rhs.m_maxval;
    m_trginfo = rhs.m_trginfo;    // shallow copy
    m_ids     = rhs.m_ids;
    m_curval  = rhs.m_curval;
    m_lastval = rhs.m_lastval;
    m_funcptr = rhs.m_funcptr;
    m_limit   = rhs.m_limit;      // shallow copy
    m_sac     = rhs.m_sac;        // shallow copy

}


//-----------------------------------------------------------------------------
// Get and Compare the last value
//-----------------------------------------------------------------------------
bool JGVariable::changed()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::changed");

    //
    // Necessary, input data to m_curval.
    //
    bool result;
    if (m_curval == m_lastval)
        result = false;                 // equal
    else
        result = true;                  // chenged

    m_lastval = m_curval;
    return result;
}

//-----------------------------------------------------------------------------
// Trigger event
//-----------------------------------------------------------------------------
int JGVariable::trigger()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::trigger");

    m_trginfo->variable(this);

    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Set trigger information
//-----------------------------------------------------------------------------
void JGVariable::trginfo(JGTriggerInfo * info)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::trginfo");
    m_trginfo = info;
    if (m_sac != NULL)
    {
        m_sac->subject(info);
    }
    return ;
}


//-----------------------------------------------------------------------------
// Init from database.
//-----------------------------------------------------------------------------
int JGVariable::init()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::init");

    if (m_sac != NULL)
    {   // Initial PLC registers: don't set value
        m_sac->init();
        if (m_sac->format() != JGIODevice::BITSET)
        {
            m_curval = this->getv();        // from plc
        }
        if ((m_class == ECV) && (! m_initval.isNil()))
        {
            m_curval = m_initval;
            m_sac->put(m_initval);
        }
    }
    else
    {
        m_curval = m_initval;
        if (m_initval.isNil())
        {
            m_curval = this->getv();   // from memory
        }
        else
        {
            this->setv(m_curval);      // to memory
        }
    }
    m_lastval = m_curval;
    return BEE_SUCCESS;
}

//-----------------------------------------------------------------------------
// Check value in renge of the variable
//-----------------------------------------------------------------------------
bool JGVariable::validValue(JGvalue& val, int aType)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::set");

    if (type_compare(m_valtype, val.format(), aType))
    {
        if (m_valtype == ATOM_ASCII)
        {
            return true;
        }
        if (val < m_minval)
        {
            return false;
        }
        if (m_maxval < val)
        {
            return false;
        }
        return true;
    }

    return false;
}

//-----------------------------------------------------------------------------
// Set integer to value in the variable
//-----------------------------------------------------------------------------
void JGVariable::setInt(int val)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::setInt");

    m_lastval = m_curval;
    m_curval.setInt(val);
    if (m_sac != NULL)
    {
        m_sac->put(m_curval);
    }
    return ;
}

//-----------------------------------------------------------------------------
// Culculate integer to value in the variable
//-----------------------------------------------------------------------------
int JGVariable::inc()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::inc");

    int i = this->getv().getInt();
    i++;
    this->setInt(i);
    return i;
}

//-----------------------------------------------------------------------------
int JGVariable::dec()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::dec");

    int i = this->getv().getInt();
    i--;
    this->setInt(i);
    return i;
}

//-----------------------------------------------------------------------------
int JGVariable::add(int n)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::add");

    int i = this->getv().getInt();
    i += n;
    this->setInt(i);
    return i;
}

//-----------------------------------------------------------------------------
int JGVariable::sub(int n)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::sub");

    int i = this->getv().getInt();
    i -= n;
    this->setInt(i);
    return i;
}

//-----------------------------------------------------------------------------
// Set value in the variable
//-----------------------------------------------------------------------------
void JGVariable::setv(JGvalue& val, bool hostupd)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::setv");

    if (m_sac != NULL)
    {
        m_sac->put(val);
    }
    m_lastval = m_curval;
    m_curval = val;
    m_hostupd = hostupd;
    return ;
}

//-----------------------------------------------------------------------------
// Get value
//-----------------------------------------------------------------------------
JGvalue& JGVariable::getv()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::getv");
    BS2Atom * atom = NULL;
    if (m_sac != NULL)
    {   // Read from PLC
        m_lastval = m_curval;
        m_curval = m_sac->get();
    }
    else if (m_funcptr != NULL)
    {
        m_lastval = m_curval;
        atom = m_funcptr(this, NULL);
        if (atom == NULL)
        {
            TRACE_ERROR((_TX("The variable(%s) did not get value.\n"),
                         this->charName()));
        }
        else
        {   // No value from atom
            m_curval = *atom;
            delete atom;
        }
    }
    return m_curval;
}

//-----------------------------------------------------------------------------
// Get value in atom
//-----------------------------------------------------------------------------
BS2Atom * JGVariable::getAtom(void * arg)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::getAtom");
    BS2Atom * atom = NULL;
    if (m_sac != NULL)
    {
        m_lastval = m_curval;
        m_curval = m_sac->get();
        atom = BS2Atom::factory(m_curval);
    }
    else if (m_funcptr != NULL)
    {
        m_lastval = m_curval;
        atom = m_funcptr(this, arg);
        if (atom == NULL)
        {
            TRACE_ERROR((_TX("The variable(%s) did not get value.\n"),
                         this->charName()));
        }
    }
    else
    {
        BS2value val(m_curval);
        atom = val.getAtom(m_valtype);
    }
    return atom;
}

//-----------------------------------------------------------------------------
// Check chenged and Issue trigger
//-----------------------------------------------------------------------------
int JGVariable::sense()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::sense");
    int result;
    if (m_hostupd.value())
    {   // New equipment constant by Host
        m_hostupd = false;
        if (m_class == ECV)
        {
            this->getv();
            return BEE_SUCCESS;
        }
        else if (m_class == SV)
        {
            m_lastval = m_initval;
            m_curval = m_initval;
            return BEE_SUCCESS;
        }
    }

    if (m_sac != NULL)
    {   // Read from PLC
        result = m_sac->sense();
    }
    else if (m_funcptr != NULL)
    {
        BS2Atom * atom = m_funcptr(this, NULL);
        if (atom == NULL)
        {
            TRACE_ERROR((_TX("The variable(%s) did not get value.\n"),
                         this->charName()));
        }
        else
        {   // No value from atom
            JGvalue val(*atom);
            delete atom;
            if (m_curval != val)
            {
                if (m_trginfo != NULL)
                {
                    m_trginfo->changed();
                }
                m_lastval = m_curval;
            }
        }
    }
    else
    {   // On memory
        if (m_curval != m_lastval)
        {
            if (m_trginfo != NULL)
            {
                m_trginfo->changed();
            }
            m_lastval = m_curval;
        }
        result = BEE_SUCCESS;
    }
    return result;
}

//-----------------------------------------------------------------------------
// Create V item
//-----------------------------------------------------------------------------
BS2Item * JGVariable::createVItem(void * arg)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::createVItem");
    BS2Atom * atom = this->getAtom(arg);
    if (atom == NULL)
    {
        atom = new BS2Ascii(_TX("Sorry, JYUGEM could not get value."));
    }
    BS2Item * item = BS2Item::factory(_TX("V"), atom);

    return item;
}

//-----------------------------------------------------------------------------
// Create variable name item for S1F12
//-----------------------------------------------------------------------------
BS2Item * JGVariable::createNameItem()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::createNameItem");
    BS2ListItem * listitem = new BS2ListItem;
    BS2Item * item;

    item = BS2Item::factory(_TX("SVID"), BS2Atom::factory(m_ecsvid));
    listitem->add(item);
    item = BS2Item::factory(_TX("SVNAME"), new BS2Ascii(m_name));
    listitem->add(item);
    item = BS2Item::factory(_TX("UNITS"), new BS2Ascii(m_unit));
    listitem->add(item);

    return listitem;
}

//-----------------------------------------------------------------------------
// Create nil item for variable name list (S1F12)
//-----------------------------------------------------------------------------
BS2Item * JGVariable::nilNameItem(JGid& svid)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::nilNameItem");
    BS2ListItem * listitem = new BS2ListItem;
    BS2Item * item;

    item = BS2Item::factory(_TX("SVID"), BS2Atom::factory(svid));
    listitem->add(item);
    item = BS2Item::factory(_TX("SVNAME"), new BS2Ascii);   // Set empty item
    listitem->add(item);
    item = BS2Item::factory(_TX("UNITS"), new BS2Ascii);    // Set empty item
    listitem->add(item);

    return listitem;
}

//-----------------------------------------------------------------------------
// Create equipment constant name item for S2F30
//-----------------------------------------------------------------------------
BS2Item * JGVariable::createEcvName()
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::createEcvName");
    BS2ListItem * listitem = new BS2ListItem;
    BS2Item * item;

    item = BS2Item::factory(_TX("ECID"), BS2Atom::factory(m_ecsvid));
    listitem->add(item);
    item = BS2Item::factory(_TX("ECNAME"), new BS2Ascii(m_name));
    listitem->add(item);

    item = BS2Item::factory(_TX("ECMIN"), m_minval);
    listitem->add(item);

    item = BS2Item::factory(_TX("ECMAX"), m_maxval);
    listitem->add(item);

    item = BS2Item::factory(_TX("ECDEF"), m_initval);
    listitem->add(item);
    item = BS2Item::factory(_TX("UNITS"), new BS2Ascii(m_unit));
    listitem->add(item);

    return listitem;
}

//-----------------------------------------------------------------------------
// Create nil item for equipment constant name (S2F30)
//-----------------------------------------------------------------------------
BS2Item * JGVariable::nilEcvName(JGid& ecid)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::nilEcvName");
    BS2ListItem * listitem = new BS2ListItem;
    BS2Item * item;

    item = BS2Item::factory(_TX("ECID"), BS2Atom::factory(ecid));
    listitem->add(item);
    item = BS2Item::factory(_TX("ECNAME"), new BS2Ascii);  // Set empty item
    listitem->add(item);
    item = BS2Item::factory(_TX("ECMIN"), new BS2Ascii);
    listitem->add(item);
    item = BS2Item::factory(_TX("ECMAX"), new BS2Ascii);
    listitem->add(item);
    item = BS2Item::factory(_TX("ECDEF"), new BS2Ascii);
    listitem->add(item);
    item = BS2Item::factory(_TX("UNITS"), new BS2Ascii);
    listitem->add(item);

    return listitem;
}

//-----------------------------------------------------------------------------
// Print items of the variable
//-----------------------------------------------------------------------------
void JGVariable::printOn(string& buf, int mode)
{
    TRACE_FUNCTION(TRL_LOW, "JGVariable::printOn");
    ACE_UNUSED_ARG(mode);

    BCHAR * className = _TX("V");
    if (m_class == SV)
    {
        className = _TX("SV");
    }
    else if (m_class == ECV)
    {
        className = _TX("ECV");
    }
    else if (m_class == DVVAL)
    {
        className = _TX("DVVAL");
    }
    else if (m_class == PV)
    {
        className = _TX("PV");
    }
    m_id.get(buf);
    buf += _TX(" ");
    buf += className;
    buf += _TX(" ");

    const BCHAR * typeName = b_value::formatStr(m_valtype);
    if (typeName == NULL)
    {
        typeName = _TX("UNKNOWN-TYPE");
    }
    buf += typeName;
    buf += _TX(" ");

    string current;
    m_curval.get(current);
    buf += current;

    return ;
}

