// File: /include/js/Shared/Calls/Calls.js
// Desc: Calls
// $Revision: 35$
// $Date: 5/14/2007 12:10:34 PM$
// $Author: Donnie Tognazzini$
// $NoKeywords$

/******************************************************************************
  Constants
 ******************************************************************************/

// Call Review State enum
var CL_REVIEW_STATE_NEW             = 'N';
var CL_REVIEW_STATE_SAVED           = 'S';
var CL_REVIEW_STATE_DELETED         = 'D';

// Caller Phone Type
var CL_PHONE_TYPE_UNKNOWN_PHONE     = 'U';
var CL_PHONE_TYPE_RESIDENTIAL_PHONE = 'H';
var CL_PHONE_TYPE_BUSINESS_PHONE    = 'W';
var CL_PHONE_TYPE_MOBILE_PHONE      = 'C';
var CL_PHONE_TYPE_FAX_PHONE         = 'F';


/******************************************************************************
  Functions
 ******************************************************************************/

function CL_GetPhoneTypeAsString( callerPhoneTypeEnum )
{
    switch ( callerPhoneTypeEnum )
    {
    case CL_PHONE_TYPE_RESIDENTIAL_PHONE:
        return "Home";
    case CL_PHONE_TYPE_BUSINESS_PHONE:
        return "Work";
    case CL_PHONE_TYPE_MOBILE_PHONE:
        return "Cell";
    case CL_PHONE_TYPE_FAX_PHONE:
        return "Fax";
    case CL_PHONE_TYPE_UNKNOWN_PHONE:
    default:
        return "Unknown";
    }
}

/******************************************************************************
  Definitions
 ******************************************************************************/

/******************************************************************************
  CL_CallId c'tor

    Can be called with the listed parameters or exactly 1 parameter containing
    an XML DOM tree.

    Exceptions:
        CL_EX_FailedParsingCallId
 ******************************************************************************/
function CL_CallId( timeStamp, callInstance )
{
    try
    {
        this.m_time = timeStamp;
        this.m_inst = callInstance;

        if ( arguments.length == 1 )
        {
            // Define all the variables
            this.m_time = 0;
            this.m_inst = 0;

            // In this case, the first argument is actually an XML DOM node
            XML_InitializeMembersFromXMLElement( arguments[0], this, "cid" );

            // make integer values integers
            this.m_time = parseInt( this.m_time );
            this.m_inst = parseInt( this.m_inst );
        }
        this.stringValue = "call_" + this.m_time + "_" + this.m_inst;
    }
    catch ( e )
    {
        throw new CL_EX_FailedParsingCallId( "CL_CallId::CL_CallId( )", e );
    }
}

CL_CallId.prototype =
{
    asXML: function(){ return UTILS.propertiesAsXml( this, ['time', 'inst'], 'cid' ); },

    getTimeStamp: function(){ return this.m_time; },

    getCallInstance: function(){ return this.m_inst; },

    toString: function() { return this.stringValue; },

    clone: function( )
    {
        return new CL_CallId( this.m_time, this.m_inst );
    },

    equals: function( rhs )
    {
        return this.m_time == rhs.m_time && this.m_inst == rhs.m_inst;
    }
};

// put out here so it is a 'static' class method.  ie. available even w/o a CL_CallId object.
CL_CallId.fromString = function( callerIdString )
{
    try
    {
        // verify the input
        if ( typeof callerIdString != 'string' )
        {
            throw new CL_EX_FailedParsingCallId( "'" + callerIdString + "' is not a valid CL_CallId string" );
        }

        // parse the input
        var a = callerIdString.split( /_/ );

        if ( a.length != 3 )
        {
            throw new CL_EX_FailedParsingCallId( "'" + callerIdString + "' is not a valid CL_CallId string" );
        }

        return new CL_CallId( a[1], a[2] );
    }
    catch ( e )
    {
        EX_ASSERT_NO_EXCEPTIONS( e, "CL_CallId.fromString( )" );
    }
};


/******************************************************************************
  CL_Call c'tor

    Can be called with the listed parameters or exactly 1 parameter containing
    an XML DOM tree.

    Exceptions:
        CL_EX_FailedParsingCall
 ******************************************************************************/
function CL_Call( callId,
                  formattedDate,
                  formattedTime,
                  callReviewStatus,
                  durationSecs,
                  outcome,
                  formattedCallerId,
                  callerName,
                  phoneType,
                  messagePrimaryFetch,
                  messageSecondaryFetch,
                  location )
{
   try
   {
      this.m_cid             = callId;
      this.m_fmtDate         = formattedDate;
      this.m_fmtTime         = formattedTime;
      this.m_revStatus       = callReviewStatus;
      this.m_durSecs         = durationSecs;
      this.m_outcome         = outcome;
      this.m_fmtCallerId     = formattedCallerId;
      this.m_name            = callerName;
      this.m_phoneType       = phoneType;
      this.m_msgPri          = messagePrimaryFetch;
      this.m_msgSec          = messageSecondaryFetch;
      this.m_loc             = location;

      this.m_originalCall    = null;


      if ( arguments.length == 1 )
      {

         // Define all the variables
         this.m_cid         = null;
         this.m_fmtDate     = '';
         this.m_fmtTime     = '';
         this.m_revStatus   = '';
         this.m_durSecs     = 0;
         this.m_outcome     = '';
         this.m_fmtCallerId = '';
         this.m_name        = '';
         this.m_phoneType   = '';
         this.m_msgPri      = '';
         this.m_msgSec      = '';
         this.m_loc         = '';

         // In this case, the first argument is actually an XML DOM node
         XML_InitializeMembersFromXMLElement( callId, this, "call" );

         // make integer values integers
         this.m_durSecs = parseInt( this.m_durSecs );
      }
      if ( this.m_revStatus != CL_REVIEW_STATE_NEW &&
          this.m_revStatus != CL_REVIEW_STATE_SAVED &&
          this.m_revStatus != CL_REVIEW_STATE_DELETED  )
      {
         throw new CL_EX_InvalidReviewStatus( this.m_revStatus );
      }
   }
   catch ( e )
   {
      throw new CL_EX_FailedParsingCall( e );
   }
}

CL_Call.prototype =
{
    asXML:function( )
    {
        return UTILS.propertiesAsXml( this,
                                     ["cid",
                                      "fmtDate",
                                      "fmtTime",
                                      "revStatus",
                                      "durSecs",
                                      "outcome",
                                      "fmtCallerId",
                                      "name",
                                      "phoneType",
                                      "msgPri",
                                      "msgSec",
                                      "loc"], "call" );
    },

    getCallId: function( )
    {
        return this.m_cid;
    },

    getFormattedDate: function( )
    {
        return this.m_fmtDate;
    },

    getFormattedTime: function( )
    {
        return this.m_fmtTime;
    },

    getReviewStatus: function( )
    {
        return this.m_revStatus;
    },

    setReviewStatus: function( newStatus )
    {
        if ( newStatus !== CL_REVIEW_STATE_NEW    &&
             newStatus !== CL_REVIEW_STATE_SAVED  &&
             newStatus !== CL_REVIEW_STATE_DELETED )
        {
            throw new Error( "CL_Call::setReviewStatus() called with bogus value: " + newStatus );
        }

        if ( this.m_revStatus != newStatus )
        {
            this.keepCopyOfOriginal( );

            this.m_revStatus = newStatus;
        }

        this.checkIfBackToOriginalValues( );
    },

    revStatusUpdated: function()
    {
        return this.isPropertyUpdated('revStatus');
    },

    isPropertyUpdated: function( p )
    {
        if ( this.m_originalCall === null )
        {
            return false;
        }

        var localPropertyVariableName = 'm_' + p;

        return this[ localPropertyVariableName ] != this.m_originalCall[ localPropertyVariableName ];
    },

    getDurationSecs: function( )
    {
        return this.m_durSecs;
    },

    getOutcome: function( )
    {
        return this.m_outcome;
    },

    getFormattedCallerId: function( )
    {
        return this.m_fmtCallerId;
    },

    getCallerName: function( )
    {
        return this.m_name;
    },

    setCallerName: function( v )
    {
        if (this.m_name != v) {
            this.keepCopyOfOriginal();
            this.m_name = v;
        }
        this.checkIfBackToOriginalValues();
    },

    callerNameUpdated: function()
    {
        return this.isPropertyUpdated('name');
    },


    getPhoneType: function( )
    {
        return this.m_phoneType;
    },

    setPhoneType: function( v )
    {
        // TODO - check for valid types?
        if (this.m_phoneType != v) {
            this.keepCopyOfOriginal();
            this.m_phoneType = v;
        }
        this.checkIfBackToOriginalValues();
    },

    phoneTypeUpdated: function()
    {
        return this.isPropertyUpdated('phoneType');
    },


    getPhoneTypeAsString: function( )
    {
        return CL_GetPhoneTypeAsString( this.m_phoneType );
    },

    getPhoneTypeIcon: function( callerPhoneTypeEnum, isSelected )
    {
        if (typeof VM_RESOURCE_PHONE_ICON_HOME_W == 'undefined') {
            return ''; // only produces values when CallListView.js is loaded as well.
        }
        var type = typeof callerPhoneTypeEnum != 'undefined' ? callerPhoneTypeEnum : this.m_phoneType;
        var selected = typeof isSelected != 'undefined' ? isSelected : this.selected;

        switch ( type ) {
            case CL_PHONE_TYPE_RESIDENTIAL_PHONE:
                return selected ? VM_RESOURCE_PHONE_ICON_HOME_W : VM_RESOURCE_PHONE_ICON_HOME;

            case CL_PHONE_TYPE_BUSINESS_PHONE:
                return selected ? VM_RESOURCE_PHONE_ICON_WORK_W : VM_RESOURCE_PHONE_ICON_WORK;

            case CL_PHONE_TYPE_MOBILE_PHONE:
                return selected ? VM_RESOURCE_PHONE_ICON_CELL_W : VM_RESOURCE_PHONE_ICON_CELL;

            case CL_PHONE_TYPE_FAX_PHONE:
            case CL_PHONE_TYPE_UNKNOWN_PHONE:
            default:
                return '';
        }
    },

    getMessagePrimaryFetch: function( )
    {
        return this.m_msgPri;
    },

    getMessageSecondaryFetch: function( )
    {
        return this.m_msgSec;
    },

    getLocation: function( )
    {
        return this.m_loc;
    },

    isMarkedForUpdate: function( )
    {
        return this.m_originalCall !== null;
    },

    updatesSaved: function()
    {
        this.m_originalCall = null; // don't need this since current values have been saved.
    },

    keepCopyOfOriginal: function()
    {
        if ( this.m_originalCall === null )
        {
            this.m_originalCall = this.clone( );
        }
    },

    checkIfBackToOriginalValues: function()
    {
        if ( this.m_originalCall === null )
        {
            return;
        }

        if ( this.equals( this.m_originalCall ) )
        {
            this.m_originalCall = null; // updated back to the original call values.
        }
    },

    clone: function( )
    {
        return new CL_Call( this.m_cid.clone( ),
                            '' + this.m_fmtDate,
                            '' + this.m_fmtTime,
                            '' + this.m_revStatus,
                            0  + this.m_durSecs,
                            '' + this.m_outcome,
                            '' + this.m_fmtCallerId,
                            '' + this.m_name,
                            '' + this.m_phoneType,
                            '' + this.m_msgPri,
                            '' + this.m_msgSec,
                            '' + this.m_loc );
    },

    equals: function( call )
    {
        return this.m_cid.equals( call.m_cid )              &&
               this.m_fmtDate       === call.m_fmtDate      &&
               this.m_fmtTime       === call.m_fmtTime      &&
               this.m_revStatus     === call.m_revStatus    &&
               this.m_durSecs       === call.m_durSecs      &&
               this.m_outcome       === call.m_outcome      &&
               this.m_fmtCallerId   === call.m_fmtCallerId  &&
               this.m_name          === call.m_name         &&
               this.m_phoneType     === call.m_phoneType    &&
               this.m_msgPri        === call.m_msgPri       &&
               this.m_msgSec        === call.m_msgSec       &&
               this.m_loc           === call.m_loc;
    }
};

/******************************************************************************
  CL_CallList c'tor

    Can be called with the listed parameters or exactly 1 parameter containing
    an XML DOM tree.

    Exceptions:
        CL_EX_FailedParsingCallList
 ******************************************************************************/
function CL_CallList( xmlDOMElement )
{
    try
    {
        this.m_callList = { length: 0 };

        if ( arguments.length == 1 )
        {
            var element = xmlDOMElement.firstChild;
            for ( ; element; element = element.nextSibling )
            {
                var ELEMENT_NODE_TYPE = 1;
                if ( element.nodeType != ELEMENT_NODE_TYPE )
                {
                    continue;
                }
                this.addCall( new CL_Call( element ) );
            }
        }
    }
    catch ( e )
    {
        throw new CL_EX_FailedParsingCallList( e );
    }
}

CL_CallList.prototype =
{
    length: function( )
    {
        return this.m_callList.length;
    },

    at: function( indexOf )
    { // fetch via CL_Call, CL_CallId or index(string or int)
        var ind = indexOf;
        ind = ind.getCallId ? ind.getCallId().toString() : ind;
        return this.m_callList["CALLLIST_" + ind] || this.m_callList[ind];
    },

    addCall: function( call )
    {
        this.m_callList[this.m_callList.length] = call; // support array like access
        this.m_callList["CALLLIST_" + call.getCallId().toString()] = call;
        this.m_callList.length += 1;
    },

    asXML: function( )
    {
        var a = [];
        for (var p in this.m_callList)
            if (p.substring(0,9) == 'CALLLIST_')
                a.push(p);  // just the CALLLIST_*'s since there are extra pointers for array access and length in there.
        return UTILS.propertiesAsXml( this.m_callList, a, "calls", '');
    }
};


/******************************************************************************
  CL_CallUpdate
 ******************************************************************************/
function CL_CallUpdate( callId,
                        newReviewStatus,
                        newCallerName,
                        newPhoneType )
{
    this.m_cid       = callId;
    this.m_revStatus = newReviewStatus;
    this.m_name      = newCallerName;
    this.m_phoneType = newPhoneType;

    if ( arguments.length == 1 )
    {
        // Define all the variables
        this.m_cid       = null;
        this.m_revStatus = '';
        this.m_name      = '';
        this.m_phoneType = '';

        if (callId.getCallId) {
            // looks like we were passed a CL_Call
            var call = callId;
            if (!call.isMarkedForUpdate()) {
                // just create an update with everything.  the caller must know why they wanted this.
                this.m_cid = call.m_cid;
                this.m_revStatus = call.m_revStatus;
                this.m_name = call.m_name;
                this.m_phoneType = call.m_phoneType;
            }
            else {
                var interestingProperties = [];
                this.m_cid = call.m_cid;
                interestingProperties.push('cid');
                if (call.revStatusUpdated()) {
                    this.m_revStatus = call.m_revStatus;
                    interestingProperties.push('revStatus');
                }
                if (call.callerNameUpdated()) {
                    this.m_name = call.m_name;
                    interestingProperties.push('name');
                }
                if (call.phoneTypeUpdated()) {
                    this.m_phoneType = call.m_phoneType;
                    interestingProperties.push('phoneType');
                }
                this.currentXmlProperties = interestingProperties;
            }
        }
        else {
            // In this case, the first argument is actually an XML DOM node
            XML_InitializeMembersFromXMLElement( callId, this, "callUpdate" );
        }
    }
}

CL_CallUpdate.prototype =
{
    allXmlProperties: ["cid",
                       "revStatus",
                       "name",
                       "phoneType"],
    currentXmlProperties: null,
    asXML:function( )
    {
        var propertiesToUse = this.currentXmlProperties ? this.currentXmlProperties : this.allXmlProperties;
        return UTILS.propertiesAsXml( this, propertiesToUse, 'callUpdate' );
    },

    getCallId:function( )
    {
        return this.m_cid;
    },

    getNewReviewStatus:function( )
    {
        return this.m_revStatus;
    },

    getNewCallerName:function( )
    {
        return this.m_name;
    },

    getNewPhoneType:function( )
    {
        return this.m_phoneType;
    }
};


/******************************************************************************
  CL_CallUpdateList
 ******************************************************************************/
function CL_CallUpdateList( )
{
    this.m_callUpdateList = new Array( );
}

CL_CallUpdateList.prototype =
{
    addCallUpdate:function( callUpdate )
    {
        this.m_callUpdateList.push(callUpdate);
    },

    asXML:function( )
    {
        return UTILS.propertiesAsXml( this.m_callUpdateList, this.m_callUpdateList, 'callUpdates', '' );
    }
};
