/*
	Copyright 2008 Lee S. Barney
	
	
    This file is part of QuickConnectiPhone.

    QuickConnectiPhone is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    QuickConnectiPhone 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with QuickConnectiPhone.  If not, see <http://www.gnu.org/licenses/>.

 */

/*
 *  This section of the file contains a facade function that is a wrapper around the front 
 *  controller used to convert the parameters JSON string to a JavaScript Array before 
 *  calling the handleRequest front controller.  
 *  This method is used to call JavaScript from Objective-C.
 */
function handleJSONRequest(cmd, parametersString){
	var paramsArray = null;
	if(parametersString){
		var paramsArray = JSON.parse(parametersString);
	}
    handleRequest(cmd, paramsArray);
	//return cmd +" "+parametersString;
}
 
 
 /*
 *  This section of the file contains the front controller through which all requests for application activity are made.
 */

 function handleRequest(aCmd, paramArray){
    requestHandler(aCmd, paramArray, null);
 }
 
 function requestHandler(aCmd, paramArray, callBackData){
	if(aCmd != null){
		if(dispatchToValCF(aCmd, paramArray)){
            try{
                var data = dispatchToBCF(aCmd, paramArray, callBackData);
                if(data != 'stop'){
                    dispatchToVCF(aCmd, data, paramArray);
                }
            }
            catch(err){
                console.log(errorMessage(err));
            }
		}
		else{
			dispatchToECF(aCmd, 'validation failed');
		}
	}
}

function handleRequestCompletionFromNative(callBackString){
    callBackString = replaceAll(callBackString, '"{', '{');
    callBackString = replaceAll(callBackString, '}"', '}');
    try{
        var callBackData = JSON.parse(callBackString);
        var parameters = callBackData[2];
        var cmdParameters;
        if(callBackData[1]){
            cmdParameters = callBackData[1];
        }
        requestHandler(cmdParameters[0], parameters, callBackData);
    }
    catch(err){
        alert(err);
    }
}

/*
*   This section of the file contains the validation, security, business, view, and error controllers.
*
*/
var validationMap = new Array();
var businessMap = new Array();
var viewMap = new Array();
var errorMap = new Array();
var securityMap = new Array();


/*
* the dispatch functions are used to handle all events from the GUI, 
* all events when the server sends data back as a response to a request, 
* and all error events.
*/

//two 'global' values used if a call is made to Objective-C from within a BCF
window.curCmd = null;
window.numFuncsCalled = 0;
window.globalBCFResults = new Array();
window.globalParamArray = null;
/*
 *  the dispatchToBCF function serializes any asynchrounous calls made via AJAX or database access.
 *  It accumulates the results of all calls to the BCF's into a results array and then returns
 *  it after all BCF's have been called.
 */
function dispatchToBCF(aCmd, paramArray, callBackData){
    window.curCmd = aCmd;
    if(paramArray){
        window.globalParamArray = paramArray;
    }
    else{
        window.globalParamArray = new Array();
    }
	var results = new Array();
    window.numFuncsCalled = 0;
    if(callBackData){
        if(callBackData[0]){
            if(callBackData[1]){
                var accumulatedDataFromCallback = callBackData[1][3];
                if(accumulatedDataFromCallback && accumulatedDataFromCallback.length > 0){
                    results = accumulatedDataFromCallback;
                }
            }
            if(results.length == 0){
                //results should always be an array.  The [] make sure that it is.
                results = [callBackData[0]];
            }
            else{
                results.push(callBackData[0]);
            }
        }
        if(callBackData[1]){
            window.numFuncsCalled = callBackData[1][1];
        }
    }
    var stop = false;
	if(aCmd){
		var commandList = businessMap[aCmd];
		callFunc = function(data){
			if(data){
				results.append(data);
                //store off the results just in case the next call is to the Objective-C side
                window.globalBCFResults = results;
			}
			if(window.numFuncsCalled < commandList.length){
				var funcToCall = commandList[window.numFuncsCalled];
				window.numFuncsCalled++;
				var result = null;
				try{
					result = funcToCall(paramArray, results);
				}
				catch(err){
					dispatchToECF('runFailure', err.message);
				}
				/* functions that are completely synchronous must return
				 *  a value.  Functions that call asynchronous methods such as 
				 *  using the ServerAccessObject or the DatabaseAccessObject
				 *  must return nothing.
				 *  The callback functions for the asynchronous calls
				 *  must make a call to callFunc.
				 */
				if(result != null){
					results[results.length] = result;
					callFunc();
				}
                else{
                    stop = true;
                }
			}
		}
		if(commandList && commandList.length > 0){
			callFunc();
		}
	}
    if(stop){
        return 'stop';
    }
    return results;
}

function dispatchToVCF(aCmd, data, paramArray){
    /*
    * the command will be null if dispatch is 
    * being called due to a successful return 
    * from the server or the database.
    */
    if(aCmd){
		var vcfFuncList = viewMap[aCmd];
		if(vcfFuncList == null){
			vcfFuncList = new Array();
		}
        var numFuncs = vcfFuncList.length;
        for(var i = 0; i < numFuncs; i++){
            var retVal = null;
			try{
                var func = vcfFuncList[i];
				retVal = func(data, paramArray);
			}
			catch(err){
				logError(err);
			}
            /*
            * a view control function can return 'stop' or nothing.
            * if 'stop' is returned then no more vcfs will be called
            * from the vcf stack
            */
            if(retVal && retVal == 'stop'){
                break;
            }
        }
    }
}

function dispatchToECF(errorCommand, errorMessage){
    var errorFunc = errorMap[errorCommand];
    if(errorFunc){
        return errorFunc(errorMessage);
    }
}
	
/*  
 * The checkSecurity is responsible for executing all of the default and 
 * any custom security functions associated with a specific command.
 */
function dispatchToSCF(securityCommand, data){
	return check(securityCommand, 'security', data);
}

/*  
 * The checkSecurity is responsible for executing all of the default and 
 * any custom security functions associated with a specific command.
 */
function dispatchToValCF(validationCommand, paramArray){
	return check(validationCommand, 'validation', paramArray);
}

/*
 * This function is not intended to be called directly by the programmer.  Do not use it.
 */
function check(command, type, data){
	var retVal = true;
	/*
	 * execute all of the default functions that apply to all commands if there are any default functions defined.
	 */
	var map = securityMap;
	if(type == 'validation'){
		map = validationMap;
	}
	var defaultFuncs = map['default'];
	if(defaultFuncs){
		var numFuncs = defaultFuncs.length;
		for(var i = 0; i < numFuncs; i++){
            retVal = defaultFuncs[i](command, data);
			if(retVal == false){
				break;
			}
		}
	}
	/*
	 * if the default functions have passed then do those specifically for the command
	 */
	if(retVal == true){
		commandFuncs = map[command];

		if(commandFuncs){
			var numFuncs = commandFuncs.length;
			for(var i = 0; i < numFuncs; i++){
				retVal = commandFuncs[i](data);
				if(retVal == false){
					break;
				}
			}
		}
	}
	return retVal;
}