/**
 *  base.js: this is the base client
 *
 *  Last Checked In By $Author: sasman $
 *  $Date: 2005/01/03 18:12:19 $
 *  $Revision: 1.26 $
 *
 *  (c) 2004 Copyright Basis Applied Technology
 *  CONFIDENTIAL INFORMATION
 *  All rights are reserved. Copying or other reproduction of
 *  this program except for archival purposes is prohibited
 *  without the prior written consent of Basis Applied Technology
 *
 *  Basis Applied Technology
 *  Gibsons, BC
 *  604.886.0721
 *
 *  REVISION HISTORY
 *
 *  $Log: base.js,v $
 *  Revision 1.26  2005/01/03 18:12:19  sasman
 *  *** empty log message ***
 *
 *  Revision 1.25  2005/01/03 17:57:39  sasman
 *  changed doDebug to default to false
 *
 *  Revision 1.24  2004/12/15 21:29:34  sasman
 *  major rights revision. added rights caching, flushing. deprecated ordinal rules for system object.
 *
 *  Revision 1.23  2004/11/23 14:24:25  sasman
 *  added instance updating and fixed minor error handling bug
 *
 *  Revision 1.22  2004/11/16 13:46:41  sasman
 *  *** empty log message ***
 *
 *  Revision 1.20  2004/11/03 17:18:20  sasman
 *  more preparation for obfuscation compatibility
 *
 *  Revision 1.19  2004/11/03 09:10:45  sasman
 *  prepared scripts for obfuscation and checking in initial _c files
 *
 *  Revision 1.18  2004/11/01 16:36:55  sasman
 *  *** empty log message ***
 *
 *  Revision 1.17  2004/09/14 11:15:37  sasman
 *  mostly added semi-colons for obfuscation and fxing media upload bugs
 *
 *  Revision 1.16  2004/09/07 01:11:25  sasman
 *  *** empty log message ***
 *
 *  Revision 1.15  2004/08/17 20:53:26  sasman
 *  *** empty log message ***
 *
 *  Revision 1.13  2004/08/10 18:37:22  sasman
 *  *** empty log message ***
 *
 *  Revision 1.11  2004/07/28 17:10:21  sasman
 *  *** empty log message ***
 *
 *  Revision 1.10  2004/07/24 00:01:27  sasman
 *  *** empty log message ***
 *
 *  Revision 1.9  2004/07/19 20:41:11  sasman
 *  *** empty log message ***
 *
 *  Revision 1.8  2004/07/16 00:45:36  sasman
 *  *** empty log message ***
 *
 *  Revision 1.7  2004/07/15 01:57:40  sasman
 *  *** empty log message ***
 *
 *  Revision 1.6  2004/07/14 02:36:58  sasman
 *  *** empty log message ***
 *
 *  Revision 1.5  2004/07/12 23:29:46  sasman
 *  *** empty log message ***
 *
 *  Revision 1.4  2004/07/09 03:53:20  sasman
 *  *** empty log message ***
 *
 *  Revision 1.3  2004/07/08 20:56:26  sasman
 *  *** empty log message ***
 *
 *  Revision 1.2  2004/06/22 20:30:05  sasman
 *  *** empty log message ***
 *
 *  Revision 1.1  2004/06/18 03:12:38  sasman
 *  *** empty log message ***
 *
 *
 */

 /**
 * @todo: no pinging if not logged in!
 */
core.loadUnit('xmlrpccore');
core.loadUnit('sysutils');

//////////////////////////////////////////////////////////////////////////////////////////////

/** */
base = {};

/** set to true to turn on alerts and debug messages. */
base.doDebug = false;

/**
* a settable callback for when the user logs in or out.
*/
base.cbLogin = function(){};

/** a settable callback for when the user logs in or out.*/
base.cbLogout = function(){};

/** a settable callback that fires when the message count is updated from a routine server ping. */
base.cbMessageCount = function(n){};

/** a callback that is fired when a fault occurs in the base object. what is received is an object
 containing 2 properties: faultCode, and faultString */
base.cbError = function(e){};

/** a callback that is fired to set status text */
base.status = function(s){};

/** the server used for system level rpc calls (login, logout, etc...) */
base.system_server  = 'services/svc_system.php';

/** the server used for content rpc calls */
base.content_server  = 'services/svc_content.php';

/** the 'ping' frequency in milliseconds. this is the frequency at which the client refreshes the session.
* in order to prevent session timeouts when in the application, call base.pingServer(). calling pingServer(false)
* will reset the ping timer and make a call immediately.
*
* new messages are also checked along with the ping so set it to whatever your message check frequency is at...
*/
base.ping_frequency = 300000; // 5 minutes

/** @HACK: by default the content centre is 'undefined'. setting this to true loads all the extra content centre
* bits to extend content objects. **/
CONTENT_CENTRE = false;

//////////////////////////////////////////////////////////////////////////////////////////////

/**
* initialize base with a properties object
*
* the properties object must contain the following:
*   oCurrentUser:   the current user object
*   iVisitorID:     the default user id
*   sKey:           the base session key
*   iNewMessages:   the count of new messages for the user
*   theme:          colors, fonts, border style and the like
*   aRightTypes:    the installed right types.
*/
base.init = function(obj)
{
    base.wait_for_next_ping = true;
    base.active_session     = false;
    base.new_messages       = 0;

    base.current_user = obj['oCurrentUser'];
    base.visitor_id   = obj['iVisitorID'];
    base.key          = obj['sKey'];
    base.new_messages = obj['iNewMessages'];

    base.theme = core.rTheme(obj.theme);

    base.m_rightTypes = obj['aRightTypes'];

    // setup the ping timer
    //!!!base._initping();

    // add some events to stave off inactivity session timeout
    //!!!core.addEvent(document, "keypress", base.pingServer, false);
    //!!!core.addEvent(document, "mousemove", base.pingServer, false);

    core.addEvent(window, "unload", base.shutdown);
};

base.initModules = function()
{
    if (base.mod_init_fns) { for (var i=0 ; i<base.mod_init_fns.length ; i++) { base.mod_init_fns[i](); } }
};

base.addModuleInitFunction = function(fn)
{
   if (!base.mod_init_fns) {base.mod_init_fns = [];}
   base.mod_init_fns[base.mod_init_fns.length] = fn;
};

/** */
base.shutdown = function()
{
    // shutdown code here...
};

/** */
base.login = function( $user, $pass, server, method, sync )
{
    var r = true;

    if (   (!$user)
        || (!$pass)
        || ($user == '')
        || ($pass == ''))
    {
        r = new XMLRPCFault();
        r['faultCode'] = 1;
        r['faultString'] = 'Please enter a username and password';
        base._handleFault( r );
    }
    else
    {
        if (!server) server = base.system_server;
        if (!method) method = 'System.Login';

        if (sync)
        {
            r = core.xmlrpc.Call(server, base.key, method, [$user, $pass]);

            if (r instanceof XMLRPCFault)
            { base._handleFault(r); }
            else
            {
                base.current_user = r['user'];
                base.new_messages = r['new_messages'];
            }
        }
        else
        {
            var oPacket = new XMLRPCPacket(server, base.key);
            var oMethod = new XMLRPCMethod(method, $user, $pass);

            oMethod.setHandler( base, base._loginHandler, ['login']);
            oPacket.addMethod( oMethod );
            oPacket.Send();
        }
    }

    return r;
};

/** */
base.logout = function(server, method, sync)
{
    server = core.rVal(server, base.system_server);
    method = core.rVal(method, 'System.Logout');
    var r  = true;

    if (sync)
    {
        r = core.xmlrpc.Call(server, base.key, method, []);
        if (r instanceof XMLRPCFault)
        { base._handleFault(r); }
        else
        {
            base.current_user = r['user'];
            base.new_messages = r['new_messages'];
        }
    }
    else
    {
        var oPacket = new XMLRPCPacket(server, base.key);
        var oMethod = new XMLRPCMethod(method);

        oMethod.setHandler( base, base._loginHandler, ['logout']);
        oPacket.addMethod( oMethod );
        oPacket.Send();
    }
    return r;
};

/** */
base.currentUser = function()
{
    return base.current_user;
};

/** */
base.loggedIn = function()
{
    return (base.current_user['ObjectID'] != base.visitor_id);
};

/** */
base.tempID = function()
{
    if (!base.tempID.id)
    { base.tempID.id = -1; }

    return (base.tempID.id--);
};

/**
* call this whenever action is taken that cancels inactivity in order
* to refresh user sessions
*/
base.pingServer = function(bWait)
{
    if (arguments.length > 0 && bWait == false)
    {
        base.wait_for_next_ping = false;
    }

    base.active_session = true;

    if (base.wait_for_next_ping == false && base.loggedIn())
    {
        base._initping();
        base._ping();
    }
};

base.newMessageCount = function()
{
    return base.new_messages;
};

base.rightTypes = function()
{
    return base.m_rightTypes;
};

base.ObtainLock = function(id, bGetObject)
{
    if (arguments.length == 1) { bGetObject = false; }

    return core.xmlrpc.Call(base.system_server, base.key, 'System.ObtainLock', [id, bGetObject]);
};

base.RefreshLock = function(id)
{
    return core.xmlrpc.Call(base.system_server, base.key, 'System.RefreshLock', [id]);
};

base.ReleaseLock = function(id)
{
    return core.xmlrpc.Call(base.system_server, base.key, 'System.ReleaseLock', [id]);
};

/**
* create a content object from an init object. the init obj must have a ContentType
* property that matches a content class exactly (ie 'TextContent'). also, the unit
* required by the cob must already be loaded.
*
* if an event packet is passed in, the object will load asyncronously and may use
* a progress dialog, etc... also, the object may not be fully initialized when the
* value is returned when using an ep.
*/
base.createCob = function( obj, div )
{
    obj.parent = div;
    obj.theme  = base.theme;
    var ret = null;
    //try {
        ret = (new Function('obj', 'return '+obj['ContentType']+'(obj)'))(obj);
   // }catch(err) {
    //    alert('The object could not be created.');
   // }
    return ret;
};

base.getDate = function()
{
    var d, s;
    d = new Date();
    s = sysutils.formatDate(d,"yyyy-mm-dd");
    s += ' ' + sysutils.padZeros(d.getHours(),2) + ':' + sysutils.padZeros(d.getMinutes(),2) + ':' + sysutils.padZeros(d.getSeconds(),2);
    return s;
};

base.parseDate = function(d)
{
    // 2004-07-13 17:46:52 (our format)
    var date;
    if (d)
    { date = new Date( getDateFromFormat(d, 'yyyy-MM-dd HH:mm:ss') ); }
    else
    { date = new Date(); }

    return date;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 'private' functions

base._loginHandler = function(oMethod, action)
{
    if (!oMethod.failed())
    {
        var r = oMethod.getResponse();
        base.current_user = r['user'];
        base.new_messages = r['new_messages'];

        if (action == 'login')
        { base.cbLogin(r); }
        else if (action == 'logout')
        { base.cbLogout(r); }
    }
    else
    {
        base._handleFault( oMethod.getResponse() );
    }
};

base._ping = function()
{
    // don't need to ping if we're not logged in, as visitor session will not expire (&& no messages)
    if (base.loggedIn())
    {
        var oPacket = new XMLRPCPacket(base.system_server, base.key);

        var mPing = new XMLRPCMethod('System.Ping', base.active_session);
        mPing.setHandler( base, base._pingResult);

        if (base.doDebug)
        {
            if (base.active_session)
            { core.debug.dump_var('application active, refreshing session'); }
            core.debug.dump_var('checking for new messages');
        }

        var mNewMessages = new XMLRPCMethod('System.NewMessages');
        mNewMessages.setHandler( base, base._receiveNewMessageCount);

        oPacket.addMethod( mPing );
        oPacket.addMethod( mNewMessages );
        oPacket.Send();

        base.wait_for_next_ping = true;
        base.active_session     = false;
    }
    else
    {
        // set a flag so the next activation will occur immediately
        base.wait_for_next_ping = false;
    }
};

base._pingResult = function(oMethod)
{
    if (oMethod.failed())
    {
        base._handleFault( oMethod.getResponse() );
    }
};

base._initping = function()
{
    if (base.ping_timer)
    { clearInterval(base.ping_timer); }

    if (base.ping_frequency > 0)
    { base.ping_timer = setInterval( base._ping, base.ping_frequency ); }
};

base._receiveNewMessageCount = function(oMethod)
{
    if (!oMethod.failed())
    {
        base.new_messages = oMethod.getResponse();
        base.cbMessageCount( base.new_messages );
    }
    else
    { base._handleFault( oMethod.getResponse() ); }
};

base._handleFault = function( oFault )
{
    if (base.doDebug)
    {
        core.debug.dump(oFault, true);
        alert('Error (' + oFault.faultCode + '): ' + oFault.faultString );
    }
    base.cbError( oFault );
};


function _isInteger(val) {
    var digits="1234567890";
    for (var i=0; i < val.length; i++) { if (digits.indexOf(val.charAt(i))==-1) { return false; } }
    return true;
};

function _getInt(str,i,minlength,maxlength) {
    for (var x=maxlength; x>=minlength; x--) {
		var token=str.substring(i,i+x);
		if (token.length < minlength) { return null; }
		if (_isInteger(token)) { return token; }
	}
	return null;
};

function getDateFromFormat(val,format)
{
	val=val+"";
	format=format+"";
	var i_val=0;
	var i_format=0;
	var c="";
	var token="";
	var token2="";
	var x,y;
	var now=new Date();
	var year=now.getYear();
	var month=now.getMonth()+1;
	var date=1;
	var hh=now.getHours();
	var mm=now.getMinutes();
	var ss=now.getSeconds();
	var ampm="";

	while (i_format < format.length) {
		// Get next token from format string
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		// Extract contents of value based on format token
		if (token=="yyyy" || token=="yy" || token=="y") {
			if (token=="yyyy") { x=4;y=4; }
			if (token=="yy")   { x=2;y=2; }
			if (token=="y")    { x=2;y=4; }
			year=_getInt(val,i_val,x,y);
			if (year==null) { return 0; }
			i_val += year.length;
			if (year.length==2) {
				if (year > 70) { year=1900+(year-0); }
				else { year=2000+(year-0); }
				}
			}
		else if (token=="MMM"||token=="NNN"){
			month=0;
			for (var i=0; i<MONTH_NAMES.length; i++) {
				var month_name=MONTH_NAMES[i];
				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
					if (token=="MMM"||(token=="NNN"&&i>11)) {
						month=i+1;
						if (month>12) { month -= 12; }
						i_val += month_name.length;
						break;
						}
					}
				}
			if ((month < 1)||(month>12)){return 0;}
			}
		else if (token=="EE"||token=="E"){
			for (var i=0; i<DAY_NAMES.length; i++) {
				var day_name=DAY_NAMES[i];
				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
					i_val += day_name.length;
					break;
					}
				}
			}
		else if (token=="MM"||token=="M") {
			month=_getInt(val,i_val,token.length,2);
			if(month==null||(month<1)||(month>12)){return 0;}
			i_val+=month.length;}
		else if (token=="dd"||token=="d") {
			date=_getInt(val,i_val,token.length,2);
			if(date==null||(date<1)||(date>31)){return 0;}
			i_val+=date.length;}
		else if (token=="hh"||token=="h") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>12)){return 0;}
			i_val+=hh.length;}
		else if (token=="HH"||token=="H") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>23)){return 0;}
			i_val+=hh.length;}
		else if (token=="KK"||token=="K") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>11)){return 0;}
			i_val+=hh.length;}
		else if (token=="kk"||token=="k") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>24)){return 0;}
			i_val+=hh.length;hh--;}
		else if (token=="mm"||token=="m") {
			mm=_getInt(val,i_val,token.length,2);
			if(mm==null||(mm<0)||(mm>59)){return 0;}
			i_val+=mm.length;}
		else if (token=="ss"||token=="s") {
			ss=_getInt(val,i_val,token.length,2);
			if(ss==null||(ss<0)||(ss>59)){return 0;}
			i_val+=ss.length;}
		else if (token=="a") {
			if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
			else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
			else {return 0;}
			i_val+=2;}
		else {
			if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
			else {i_val+=token.length;}
			}
		}
	// If there are any trailing characters left in the value, it doesn't match
	if (i_val != val.length) { return 0; }
	// Is date valid for month?
	if (month==2) {
		// Check for leap year
		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
			if (date > 29){ return 0; }
			}
		else { if (date > 28) { return 0; } }
		}
	if ((month==4)||(month==6)||(month==9)||(month==11)) {
		if (date > 30) { return 0; }
		}
	// Correct hours value
	if (hh<12 && ampm=="PM") { hh=hh-0+12; }
	else if (hh>11 && ampm=="AM") { hh-=12; }
	var newdate=new Date(year,month-1,date,hh,mm,ss);
	return newdate.getTime();
};

//--------------------------------------------------------------------

SimpleButton = function(boss, text, theme, width, height, align)
{
    var e = document.createElement('button');
    e.boss = boss;
    e.innerHTML = text;
    e.theme = theme;

    if (width) e.style.width = width;
    if (height) e.style.height = height;
    if (align) e.style.textAlign = align;

    e.reDraw = function()
    {
        this.style.font            = this.theme.ctrlFont;
        this.style.backgroundColor = this.theme.hlBgColor;
        this.style.border          = '1px ' + this.theme.bdrSolid;
        this.style.borderColor     = this.theme.getOutset();
        this.style.color           = this.theme.ctrlFgColor;
    };

    e.onmouseover = function(){this.style.cursor = core.cursors.hand;};
    e.onmouseout = function(){this.style.cursor = 'default';};

    return e;
}
