BCS.Core.Engine.addNamespace("Web");

BCS.Web.DisplayMode = {
    Edit:0,
    View:1
};

BCS.Web.BaseControl = Class.create();

/*********************************************************
 *  BaseControl
 *  This class will be the base class for all the client side
 *  compoenents that will display UI.
 *
 *  Methods:
 *      - 'load': Call this function in order to fatch data from server.
 *          this function will invoke the onLoad, onError (if needed) and onComplete functions 
 *          during the changing of the request status.
 *
 *
 *  ReadyStste values: 
 *  http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/reference/enums/readystate_enum.asp
 *
 *********************************************************/
BCS.Web.BaseControl.prototype = {

    initialize: function()
    {
    },

    // Represents the url to address when calling the 'Load' method.
    // MUST be overriden by inherite classes.
    requestUrl: '',
    
    method: 'get',
    
    onCompleteInternal: function(response, json)
    {
        var cook = BCS.Web.BrowserHelper.getCookie('BCSReqAuth');
        // If this coockie exists it means that a timeout accured 
        // and there is a need to redirect to login page.
        if (cook)
        {
            // Therefore, we initiate reload of the current window location...
            window.top.location.reload();
        }
        else if (this.owner.onComplete)
            this.owner.onComplete(response, json, this);
    },
    
    onLoadingInternal: function(response, json)
    {
        if (this.owner.onLoading)
            this.owner.onLoading(response, json, this);
    },
    
    onExceptionInternal: function(response, json)
    {
        if (this.owner.onException)
            this.owner.onException(response, json, this);
    },
    
    onUninitializedInternal: function(response, json)
    {
        if (this.owner.onUninitialized)
            this.owner.onUninitialized(response, json, this);
    },
    
    onLoadedInternal: function(response, json)
    {
        if (this.owner.onLoaded)
            this.owner.onLoaded(response, json, this);
    },
    
    onInteractiveInternal: function(response, json)
    {
        if (this.owner.onInteractive)
            this.owner.onInteractive(response, json, this);
    },
    
    // onComplete method, will be invoked when in case the response from server was completed successfully, 
    // can be overriden by inherite classes.
    onComplete: function(response, json, options)
    {
        // The following line exists in order to fix a bug of cache, 
        // there are cases when the onComplete event is raised before the onLoading, 
        // and then the loading overrides the changes of the onComplete.
        if (response.readyState == 4)
        {
            if (options.owner.isError(response))
            {
                options.owner.displayErrorFromResponse(response, options);
            }
            else
                $(options.clientID).innerHTML = responseText;
        }
    },
    
    // onLoading method, will be invoked in the loading status of the AJAX request, 
    // can be overriden by inherite classes.
    onLoading: function(response, json, options)
    {
        
        // The following line exists in order to fix a bug of cache, 
        // there are cases when the onComplete event is raised before the onLoading, 
        // and then the loading overrides the changes of the onComplete.
        
        if (response.readyState == 1)
        {
            var control = $(options.clientID);
            
            if(control)
            {
                control.innerHTML = '<div class="load">Loading...</div>';
                control.style.display  = "block"; 
            }
            
            control = null;
        }
    },
    
    // onException method, will be invoked in case an exception accured during processing of the AJAX request, 
    // can be overriden by inherite classes.
    onException : function(obj, error, options)
    {
        options.owner.logMessage(options.clientID, 'An ' + error.name + ' has occurred: \n' + error.message, error.description);
    },
    
    // onUninitialized method, will be invoked in the uninitialized status of the AJAX request, 
    // can be overriden by inherite classes.
    onUninitialized: function(response, json, options)
    {
        // The following line exists in order to fix a bug of cache, 
        // there are cases when the onComplete event is raised before the onLoading, 
        // and then the loading overrides the changes of the onComplete.
        if (response.readyState == 0)
        {
        }
    },
    
    // onLoaded method, will be invoked in the loaded status of the AJAX request, 
    // can be overriden by inherite classes.
    onLoaded: function(response, json, options)
    {
            // The following line exists in order to fix a bug of cache, 
        // there are cases when the onComplete event is raised before the onLoading, 
        // and then the loading overrides the changes of the onComplete.
        if (response.readyState == 2)
        {
			 var control = $(options.clientID);
			 control.style.display  = "none"; 
        }
    },
        
    // onInteractive method, will be invoked in the interactive status of the AJAX request, 
    // can be overriden by inherite classes.
    onInteractive: function(response, json, options)
    {
        // The following line exists in order to fix a bug of cache, 
        // there are cases when the onComplete event is raised before the onLoading, 
        // and then the loading overrides the changes of the onComplete.
        if (response.readyState == 3)
        {
        }
    },
    
    // getParameters method, will be invoked during the preperation of the AJAX call, 
    // should return the parameters for the url of the request.
    // in case the mathod of the request is 'GET' they will be combined to the query string of the request, 
    // else they will be added as a header to the 'POST' request.
    // can be overriden by inherite classes.
    getParameters: function(params)
    {
        return '';
    },
    
    // getPostBody method, will be invoked during the preperation of the AJAX call if the method is POST, 
    getPostBody: function(options,arguments)
    {
        var postData = this.getPostData(arguments);
        return this.createPostBody(options, postData);
    },
    
    // the getPostData returns hash table with data to post to the server.
    // can be overriden by inherite classes.
    getPostData: function(params)
    {
        return null;
    },
    
    // function creates Request POST body
    createPostBody:function(options,postData)
    {
        var postBody = '';
        
        if(postData)
        {
            var boundary = "BCS.Boundary." + $Hex(12);
            postBody = new StringBuilder();
    
            for (var key in postData) 
            {
                if(typeof(postData[key]) != "function")
                {
                    postBody.append("--");
                    postBody.append(boundary);
                    postBody.append("\r\n");
                    postBody.append("Content-Disposition: form-data;name=\"");
                    postBody.append(key);
                    postBody.append("\"");
                    postBody.append("\r\n");
                    postBody.append("\r\n");
                    postBody.append(postData[key]);
                    postBody.append("\r\n");
                }
            }
            
            postBody.append("--");
            postBody.append(boundary);
            postBody.append("--");
            this.method = 'post';
            var requestHeaders = ["Content-type",""];
            requestHeaders.push("Content-type", "multipart/form-data; boundary=" + boundary); 
            options.requestHeaders = requestHeaders;
        }
        return postBody.toString();
    },

    // Indicates whether to treat the response text as script and evaluate it.
    // can be overriden by inherite classes.
    evalScripts: false,

    // Indicates whether the request is asynchronouslly executed.
    asynchronous: true,
    
    // A collection of objects used as arguments to the status methods.
    // getArgs method, will be invoked during the preperation of the AJAX call, 
    // should return the arguments of the current request.
    // can be overriden by inherite classes.
    getArgs: function(params)
    {
        return '';
    },
    
    createOptions: function()
    {
        var options = new Object();
        options.onComplete = this.onCompleteInternal.bind(options);
        options.onLoading = this.onLoadingInternal.bind(options);
        options.onException = this.onExceptionInternal.bind(options);
        options.onUninitialized = this.onUninitializedInternal.bind(options);
        options.onLoaded = this.onLoadedInternal.bind(options);
        options.onInteractive = this.onInteractiveInternal.bind(options);
        options.method = this.method;
        options.parameters = this.getParameters(arguments);
        
        // call to getPostBody only if the method is POST
        if(this.method && this.method.toLowerCase() == "post")
            options.postBody = this.getPostBody(options,arguments);
            
        options.evalScripts = this.evalScripts;
        options.asynchronous = this.asynchronous;
        
        options.args = this.getArgs(arguments);
        options.clientID = this.clientID;
        options.owner = this;
        
        return options;
    },
    
    load: function(params, optionToAdd)
    {
   
        var options = this.createOptions(params) || '';
        
        if(optionToAdd)
        {
            Object.extend(options, optionToAdd);
        }
        var url = this.requestUrl || '';
        // add random number to all ajax URL in order to prevent them from being cache on the proxy server
        url += (url.indexOf('?') > -1 ? '&' : '?') + 'rnd=' + newUniqueId(32);
        // prompt("",url)
        BCS.Core.ConnectionManager.processRequest(url, options);
    },
    
    translateMessage:  function(messageKey)
    {
        return BCS.Web.TranslationManager.translate(messageKey,this);
    },
    
    getTranslationKeys: function()
    {
        alert("getTranslationKeys is not implemented.")
    },
    
    isError: function(response)
    {
		if(response.responseXML.getElementsByTagName('Exception').length>0)
		{
			this.displayErrorFromResponse(response, this.options);
			//alert(response.responseXML.getElementsByTagName('Exception')[0].firstChild.data)
			return true; 
		}
        var responseText = response.responseText;
        if (responseText.indexOf('null') == 0)
            return true;
        return false;
    },
    
    displayErrorFromResponse: function (response, options)
    {
        var responseText = response.responseText;
        //eval(responseText);
        var message  = response.responseXML.getElementsByTagName('Exception')[0].firstChild.data; 
        this.logMessage(this.clientID, message);
    },
    
    registerDestructor: function()
    {
        this.destructorCalled = false;
        Event.observe(window, 'unload', this.destructor.bind(this), false);
    },
    
    destructor: function()
    {
        if(this.destructorCalled)
            return;

        if (this.onDestructor)
            this.onDestructor();
            
        var obj;
        // clear all groups
        for (i=0; i< this.count; i++)
        {
            for(obj in this[i])
            {
                var _objectToDelete = this[i][obj];
                if (_objectToDelete && (typeof(_objectToDelete) != "function"))
                {
                    this.deallocateObject(_objectToDelete)
                    this[i][obj] = null;
                }
            }
        }
            
        // Clean all the rest variables.
        for(obj in this)
        {
            var _objectToDelete = this[obj];
            if (_objectToDelete && (typeof(_objectToDelete) != "function"))
            {
                this.deallocateObject(_objectToDelete)
                this[obj] = null;
            }
        }
        
        this.destructorCalled = true;
    },
    
    deallocateObject: function(objectToDeallocate)
    {
        if (objectToDeallocate != null && objectToDeallocate.destructor)
            objectToDeallocate.destructor();
    },
    
    $: function()
    {
        var elements = new Array();
        var doc = arguments[0];
        if (!doc)
            doc = document;
        if (arguments.length == 1) 
            return;

        for (var i = 1; i < arguments.length; i++) 
        {
            var element = arguments[i];
            if (typeof element == 'string')
                element = doc.getElementById(element);

            if (arguments.length == 2) 
                return element;

            elements.push(element);
        }

        return elements;

    },
    
    logMessage: function(clientID, message, details)
    {
        var element = $(clientID)
        if (!element)
            alert(clientID + '\n' + message + '\n' + details);
        else if (element)
        {
        
			
			
			//var x  = (window.screen.availWidth/2)-element.offsetWidth/2; 
			//var y  = (window.screen.availHeight/2)-element.offsetHeight/2;  
			
			//element.style.left  = x + "px"; 
			//element.style.top  = y+ "px"; 
			element.innerHTML = '<div class="errorAndIcon"><a href="javascript:void(0);" onclick="javascript:divid=\'info\';el = document.getElementById(divid);if (el.style.display == \'none\'){el.style.display = \'\';el = document.getElementById(divid);} else {el.style.display =\'none\';el = document.getElementById(divid);};return false;">Error, Please Click For Details.</a></div>' ; 
			
			var oIframe = $('info');
			var oDoc = (oIframe.contentWindow || oIframe.contentDocument);
			if (oDoc.document) oDoc = oDoc.document;
			
			new Draggable('info',{revert:false});
			//new Draggable(oDoc.body,{revert:false});
			
			oDoc.body.innerHTML = '<div  class="errBox" id="Innerinfo" ><div class="errTtlBar"><span style="float:left">Error Message:</span><a herf="#" style="float:right; cursor:pointer; color:blue;" onclick="parent.document.getElementById(\'info\').style.display =\'none\';">Close</a></div><div style="padding:5px" class="ErrorMessageClass" >'
			+ message +
			'<br/><a href="javascript:void(0);" onclick="javascript:divid=\'errordetails\';el = document.getElementById(divid);if (el.style.display == \'none\'){el.style.display = \'\';el = document.getElementById(divid);} else {el.style.display =\'none\';el = document.getElementById(divid);};return false;">More details...</a></div>'+
			'<div id="errordetails" class="errMsg" style="display:none">' +
			details +
			'</div></div>';
	
			 ; 
			element.style.display  = "block"; 
			
			 // from the shopping cart demo
			
			
			


        }
            
    },

	getPosition: function(elem)
	{
		var pos = { left:0, top:0 }
		while (elem)
		{
			if (elem.style.position == 'absolute')
				break
	
			pos.left += elem.offsetLeft
			pos.top  += elem.offsetTop
			elem = elem.offsetParent
		}
		return pos
	}
}

////////////////////////////  start of TranslationManager ///////////////////////////////////////////////////////////////////

__translationAgent = Class.create();
__translationAgent.prototype = Object.extend(__translationAgent.prototype, BCS.Web.BaseControl.prototype)
__translationAgent.prototype = Object.extend(__translationAgent.prototype, {

    initialize: function()
    {
        this.ControlName = "TMA"
        this.TranslationKeysParamName = "tk"
        this.translationKeys = null;
        this.method = "post";
        this.asynchronous = false;
        this.debugMode = true;
    },
  
    setTranslationKeys: function(translationKeys)
    {
        this.translationKeys = translationKeys;
    },
    
    
    retrieveData: function(translationKeys)
    {
        this.translationKeys = translationKeys;
        this.requestUrl = this.appURL + 'NLS.ashx?CN=' + this.ControlName;
        this.load();
        return this.translationKeys;
    },
    
    getPostData: function()
    {
        var postData = new Object();
        postData[this.TranslationKeysParamName] = Object.toJSONString(this.translationKeys);
        
        return postData;
    },
    
    onComplete: function(response, json, options)
    {
       if (response.readyState == 4)
       {
            if(response.responseText != "")
            {
                try
                {
                    var data = eval('(' + response.responseText + ')');
                    options.owner.setTranslationKeys(data)
                    data = null;
                }
                catch(e)
                {
                    if(this.debugMode)
                        alert("__translationAgent Error\nreason:" + e.message);
                }
            }
       }
    }
});



__TranslationManager = Class.create();
__TranslationManager.prototype = {

    initialize: function()
    {
        this.cache = window.top['BCS.Web.NLSCache'];
        if (!this.cache)
        {
            this.cache = new __internalCache();
            window.top['BCS.Web.NLSCache'] = this.cache;
        }
    },
    
    
    translate: function(key, control)
    {
        var trnslatedMessage = this.cache.value(key);
        
        if(!trnslatedMessage)
        {
            this.retrieveControlKeys(control);
            trnslatedMessage = this.cache.value(key);        
        }
        
        return trnslatedMessage;
    },
    
    retrieveControlKeys: function(control)
    {
        var keys = control.getTranslationKeys();
        var agent = new __translationAgent();
        var translatedKeys = agent.retrieveData(keys);
        
        if(translatedKeys != null)
        {
            for(var key in translatedKeys)
            {
                if(typeof(translatedKeys[key]) != "function")
                {
                    this.cache.add(key, translatedKeys[key]);
                }
            }
        }
        
    }
}

BCS.Web.TranslationManager = new __TranslationManager();

/*--------------------------Screen Object Agent------------------------------------*/
ScreenAgent = Class.create();
ScreenAgent.prototype = Object.extend(ScreenAgent.prototype, BCS.Web.BaseControl.prototype)
ScreenAgent.prototype = Object.extend(ScreenAgent.prototype, {

    initialize: function(appURL)
    {
        this.appURL = appURL;
        this.screenID = null;
        this.screenObject = null;
        this.controlName = "SCR";
        this.screenObjectParamName = "scr"
        this.method = "post";
        this.asynchronous = false;
        this.debugMode = true;
        this.retrieveScreen = "RSC";
        this.saveScreen = "SSC";
    },
  
    setScreenObject: function(screenObject)
    {
        this.screenObject = screenObject;
    },
    
    
    retrieveScreenData: function(screen)
    {
        this.asynchronous = false;
        this.requestUrl = this.appURL + 'SCR.ashx?' + BCS.Core.UrlParametersConstants.CONTROL_NAME + "=" + this.controlName;
        this.requestUrl += "&" + BCS.Core.UrlParametersConstants.METHOD_NAME + "=" + this.retrieveScreen;
        this.requestUrl += "&" + "sd=" + screen;        
        this.load();
        return this.screenObject;
    },
    
    saveScreenData: function(screen)
    {
        this.asynchronous = true;
        this.requestUrl = this.appURL + 'SCR.ashx?' + BCS.Core.UrlParametersConstants.CONTROL_NAME + "=" + this.controlName;
        this.requestUrl += "&" + BCS.Core.UrlParametersConstants.METHOD_NAME + "=" + this.saveScreen;
        this.requestUrl += "&" + "sd=" + screen;
        this.load();
    },
    
    
    getPostData: function()
    {
        var postData = new Object();
        postData[this.screenObjectParamName] = this.screenID;
        return postData;
    },
    
    onComplete: function(response, json, options)
    {
       if (response.readyState == 4)
       {
            if(response.responseText != "")
            {
                try
                {
                    var scrObject = eval('(' + response.responseText + ')');
                    options.owner.setScreenObject(scrObject)
                    data = null;
                }
                catch(e)
                {
                    if(this.debugMode)
                        alert("screen agent Error\nreason:" + e.message);
                }
            }
       }
    }
});

/*--------------------------Screen Object------------------------------------*/
ScreenObject = Class.create();
ScreenObject.prototype = {

    initialize: function(id, pivotObject, selectedObject, subsystem, compState)
    {
        this.id = id;
        this.cs = compState;
        this.po = pivotObject;
        this.so = selectedObject;
        this.subs = subsystem;
    },
       
    //sets the state for a component
    setComponentState: function(compName, compState)
    {
       if (!this.cs)
       {
            this.cs = new Object();
       }
       this.cs[compName] = compState;
    },
    
    //gets the state for a certain component
    getStateForComponent: function(compName)
    {
       var compState;
       if (this.cs)
       {
            compState = this.cs[compName];
       } 
       return compState;
    },
    
    hasComponentState: function()
    {
       if (this.cs)
       {
            return true;
       } 
       return false;
    }
    
}



/*--------------------------Screen Manager------------------------------------*/
var __screenObject;
//var appPath = "http://localhost/BCS.Applications.Projecteam/";

BCS.Web.ScreenManager = {

    getPageId: function() 
    {
        return window.top.$("pageId").value;
    },
    
    getScreenId: function() 
    {
        return $("ScreenObject").value;
    },
    
    getScreenObject: function() 
    { 
        if(!__screenObject)
        {
            //get current screen id from hidden field
            var scr = $("ScreenObject");
            if (scr)
            {
                var screenId = scr.value;
                //get components state by ajax using ID
                var agent = new ScreenAgent(appPath);
                var tempScreen = new ScreenObject(screenId, "0.0.0", "0.0.0", "None", "");
                var screenObj = agent.retrieveScreenData(Object.toJSONString(tempScreen));
                if(screenObj != null)
                {
                    __screenObject = new ScreenObject(screenObj.id, screenObj.po, screenObj.so, screenObj.subs, screenObj.cs);
                }
                Event.observe(window.top, 'beforeunload', this.updateScreenObject.bind(this), false);
            }
        }
        return __screenObject;
    },
    
    registerComponent: function(componentName, component)
    {
        if (!this.registeredComponents)   
        {
            this.registeredComponents = new Object();
        }
        this.registeredComponents[componentName] = component;
    },
  
    //returns bool that indicates whether we need to initialize 
    //the components in the screen or not
    //if the user pressed the back button, we don't need init  
    needsInit: function()
    {
        var requiresInitialization = true;
        if (this.getScreenObject().hasComponentState())
        {
            requiresInitialization = false;
        }
        return requiresInitialization;
    },
    
    
    //loads all states for registered components
    loadScreenObject: function()
    {
        if (this.getScreenObject()!=null)
        {
            if (this.registeredComponents)   
            {
               for(var key in this.registeredComponents)
                {
                    component = this.registeredComponents[key];
                    if (component)
                    {
                        var objectState = this.getScreenObject().getStateForComponent(key);
                        component.setState(objectState);
                    }
                }
            }
        }
    },
    
    //will be called on page onunload
    updateScreenObject: function() 
    {
        var componentState;
        var screenObject = this.getScreenObject();
        if (screenObject!=null)
        {
            if (this.registeredComponents)   
            {
               for(var key in this.registeredComponents)
                {
                    component = this.registeredComponents[key];
                    if (component)
                    {
                        componentState = component.getState();
                        screenObject.setComponentState(key, componentState);
                    }
                }
            }
        }
        //save components state by ajax 
        var agent = new ScreenAgent(appPath);
        var screenObj = agent.saveScreenData(Object.toJSONString(screenObject));
    }
}

BCS.Web.FileHandler = Class.create();
BCS.Web.FileHandler.prototype = {
    initialize: function()
    {
    },
    
    download: function(documentObjectIdentifier)
    {
        var url = appPath + "Pages/FileHandling/FileDownload.aspx?d=" + documentObjectIdentifier;
        window.open(url , "download","width=800,height=600");
    },
    
    getDownloadUrl: function(documentObjectIdentifier)
    {
        var url = appPath + "Pages/FileHandling/FileDownload.aspx?d=" + documentObjectIdentifier;
        return url;
    }
}

Object.extend(Element, {
    // Following method will make sure that browsers that doesn't support innerText property 
    // will support setting the inner text value by using the 'textContent'  property of the element (if supported of course)
    setText: function(element, text) 
    {
        if (element.innerText != undefined && typeof(element.innerText) != 'undefined')
            element.innerText = text;
        else if (element.textContent != undefined && typeof(element.textContent) != 'undefined')
            element.textContent = text;
    },
    getText: function(element) 
    {
        if (element.innerText != undefined && typeof(element.innerText) != 'undefined')
            return element.innerText;
        else if (element.textContent != undefined && typeof(element.textContent) != 'undefined')
            return element.textContent;
    }
});

BCS.Web.IObject = Class.create();
BCS.Web.IObject.prototype = Object.extend(BCS.Web.IObject.prototype, BCS.Web.BaseControl.prototype)
BCS.Web.IObject.prototype = Object.extend(BCS.Web.IObject.prototype, {
    
    initialize:function(objectIdentifier)
    {
        this.oid = objectIdentifier;
        this.discussionCounter = false;
    },
    getParameters: function()
    {
        var url = BCS.Core.UrlParametersConstants.CONTROL_NAME + "=" + BCS.Core.UrlParametersConstants.CONTROL_NAME_GRID
        url += "&" + BCS.Core.UrlParametersConstants.METHOD_NAME + "=" + BCS.Core.UrlParametersConstants.METHOD_NAME_REFERENCE_TO_OBJECT_DISPLAY_VALUE;

        var objectIdentifier = arguments[0][0];
        if (objectIdentifier)
        {
            url += "&" + BCS.Core.UrlParametersConstants.REFERENCED_OBJECTIDENTIFIER + "=" + objectIdentifier;
        }
        if (this.discussionCounter == true)
        {
            url += "&" + BCS.Core.UrlParametersConstants.COMMENT_TYPE + "=" + BCS.Web.Comments.CommentType.Discussion;        
        }
        return url;
    },
    displayValues: function()
    {
        if (this.oid == '0.0.0')
            return '';
        this.displayValue = '';
        this.asynchronous = false;
        this.requestUrl = './GetObjectInformation.ashx';
        this.load(this.oid, {callback: this.setDisplayValues.bind(this), callbackParameters: {}});
        return this.displayValue;
    },

    displayDiscussionCounter: function()
    {
        if (this.oid == '0.0.0')
            return '';
        this.discussionCounter = true;
        this.displayValues();
    },

    onComplete: function(response, json, options)
    {
        var data = eval('(' + response.responseText+ ')');
        options.callback(data, options.callbackParameters);
    },
    setDisplayValues: function(data)
    {
        this.displayValue = data.value;
    }
});
