/* 
* gi2spring sample application
*/ 

// ------------------------------------------------------------------- global
/**
* logger for development under the GI IDE
*/
var _LOG = jsx3.util.Logger.getLogger("gi2spring");



/**
* startup, called on startup  
*/
function startup() {
  gi2spring.getJSXByName('tabErrors').setVisibility(jsx3.gui.Block.VISIBILITYHIDDEN,true) ;
  populateHome() ;
}
/**
* home tab , called on startup and when home tab is clicked
*/
function populateHome() {
  eg.displayPricesService.call() ;
}
/**
* called from execute button on price increase tab
*/
function doPriceIncrease() {
  eg.priceincreaseService.call() ;
}
// ------------------------------------------------------------------- mapping services
jsx3.lang.Package.definePackage(
  "eg.displayPricesService",                //the full name of the package to create
  function(service) {          //name the argument of this function

    //call this method to begin the service call (eg.service.call();)
    service.call = function() {
      var objService = new jsx3.net.Service("JSXAPPS/gi2spring/rules/displayprices.rule","");

      //set the namespace for the server (change this to run the rule in context of another server)
      objService.setNamespace("gi2spring");

      //subscribe and call
      objService.subscribe(jsx3.net.Service.ON_SUCCESS, service.onSuccess);
      objService.subscribe(jsx3.net.Service.ON_ERROR, service.onError);
      objService.subscribe(jsx3.net.Service.ON_INVALID, service.onInvalid);
      objService.doCall();
    };


    /**
    *call this method to have the service process a pre-existing document
    */
    service.processInbound = function(inboundDocument) {

	var objService = new jsx3.net.Service("JSXAPPS/gi2spring/rules/displayprices.rule","");

      //set the namespace for the server (change this to run the rule in context of another server)
      objService.setNamespace("gi2spring");


      // run the ruleset against the document passed from caller
      objService.setInboundDocument(inboundDocument);
      //process inbound document 
      objService.doInboundMap() ;

      //update screen
      service.updateUI(inboundDocument) ;
    };

   /**
   * update screen on successful price list
   */
    function service.updateUI(responseXML) {
          //update status
          setStatus("The service call was successful.");
          // update scalars from map returned
          setScalar('textCurrentTime','now',responseXML) ;
          // repaint fields whose data was updated by the rule
          gi2spring.getJSXByName('productList').repaint() ;
    }


    /**
     * event handler
     */
    service.onSuccess = function(objEvent) {
      // get document from event	
      var responseXML = objEvent.target.getInboundDocument();
      //update screen
      service.updateUI(responseXML) ;

   };

    service.onError = function(objEvent) {
      var myStatus = objEvent.target.getRequest().getStatus();
      setStatus("The service call failed. The HTTP Status code is: " + myStatus);
    };

    service.onInvalid = function(objEvent) {
      setStatus("The following message node just failed validation:\n\n" + objEvent.message);
    };

  }
);



jsx3.lang.Package.definePackage(
  "eg.priceincreaseService",                //the full name of the package to create
  function(service) {          //name the argument of this function

    //call this method to begin the service call (eg.service.call();)
    service.call = function() {


      // validate current input ...
      var jsxPercentage = gi2spring.getJSXByName('percentage');


      if (! jsxPercentage.doValidate()  ) {
	// find the errors in our .jss dynamic properties
	var message = jsxPercentage.getServer().getDynamicProperty("typeMismatch.percentage", jsxPercentage.getValue() ) ;
	// show the error
	displayError( 'percentage', message) ;
      	return ; // early return
      }


      // no errors, create a form based on service
      var objService = new jsx3.net.Service("JSXAPPS/gi2spring/rules/priceincrease.rule","");
      objService.setNamespace("gi2spring");

      var method = objService.getMethod() ;
      var endpointURL = objService.getEndpointURL() ;
      
      // create a form 
      var form = new jsx3.net.Form(method,endpointURL) ; //
      form.server = objService.getServer() ; 
      form.setField("percentage",jsxPercentage.getValue()) ;
      form.subscribe(jsx3.net.Form.EVENT_ON_RESPONSE, service.onSuccess);
      form.subscribe(jsx3.net.Form.EVENT_ON_ERROR, service.onError);
      form.subscribe(jsx3.net.Form.EVENT_ON_TIMEOUT, service.onTimeout);
      
      // update ui
      // set status
      setStatus("Sending form ...");
      // clear last error
      gi2spring.getJSXByName("percentageError" ).setText().repaint()  ;
      
      // send to server
      form.send() ;


    };

    service.onSuccess = function(objEvent) {

      //update status
	  var objHTTP = objEvent.target;
	  var doc = objHTTP.getResponseXML() ;
	  var errorMessages = extractErrorMessages(doc,objHTTP.server);
	  if ( errorMessages.length == 0 )  {

		gi2spring.getJSXByName('tabHome').doShow() ;
		setStatus("The priceincreaseService call was successful.");
	      	gi2spring.getJSXByName('tabErrors').setVisibility(jsx3.gui.Block.VISIBILITYHIDDEN,true) ;
		// call the same service as the home tab
		eg.displayPricesService.processInbound(doc) ;

	  } else {
		// update [field]Error
		for (var field  in errorMessages)
		{
			if (field == "length" ) {
				continue ;
			}
			// show the error
			displayError( field, errorMessages[field]) ;
		}
	  	// update and show error tab
		gi2spring.getJSXByName('errorTimestamp').setText ( new Date() ,true ) ;      
		gi2spring.getJSXByName('tabErrors').setVisibility(jsx3.gui.Block.VISIBILITYVISIBLE,true) ;
		eg.errorService.call(doc) ;
	  }	  
   };

    service.onError = function(objEvent) {
      var myStatus = objEvent.target.getRequest().getStatus();
      setStatus("The priceincreaseService call failed. The HTTP Status code is: " + myStatus);
    };

    service.onInvalid = function(objEvent) {
      setStatus("The priceincreaseService message node just failed validation:\n\n" + objEvent.message);
    };

    service.onTimeout = function(objEvent) {
      setStatus("The priceincreaseService message node just timed out:" );
    };

  }
);




jsx3.lang.Package.definePackage(
  "eg.errorService",                //the full name of the package to create
  function(service) {          //name the argument of this function

    //call this method to begin the service call (eg.service.call();)
    service.call = function(inboundDocument) {
      var objService = new jsx3.net.Service("JSXAPPS/gi2spring/rules/error.rule","");

      //set the namespace for the server (change this to run the rule in context of another server)
      objService.setNamespace("gi2spring");
      
      // run the ruleset against the document passed from caller
      objService.setInboundDocument(inboundDocument);
      //process inbound document 
      objService.doInboundMap() ;
      // no need for callbacks, simply force repaint 	
      gi2spring.getJSXByName('errors').repaint() ;
      gi2spring.getJSXByName('trace').repaint() ;

    };
  }
);


// ------------------------------------------------------------------- utility methods



/**
* update the gui object
* referred to by jsxName with the value retrieved from the map message 
*/
function setScalar(jsxName,key,doc)  {

  var xpath= "/map/entry[string='"
     + key
     + "']/*[position() = 2]" ;

  var val = doc.selectSingleNode(xpath).getValue() ;

  gi2spring.getJSXByName(jsxName).setText(val).repaint();
}


/**
* set status gui widget value
*/
function setStatus(text)  {
      gi2spring.getJSXByName('textStatus').setText(text).repaint();
}

/**
* returns a map of error messages indexed by field 
* 
* if present tokens such as {0}, {1}, {n} will be replaced with the nth element of this vararg array
* Parameters:
* doc – xml doc containing Spring bind exception
* server  
*/
function extractErrorMessages(doc, server) {

	var returnMap = new Object() ;
	returnMap.length = 0 ;
	
	// where to find exceptions
	var xpathBindException = '/map/entry/org.springframework.validation.BindException' ;

        // where to find the field in error
	var xpathFieldError = 'errors/org.springframework.validation.FieldError/field' ;

	// where to find the list of message codes
	var xpathFieldErrorCodes = "errors/org.springframework.validation.FieldError/codes/string" ;

	// get the rejected value
	var xpathRejectedValue = "errors/org.springframework.validation.FieldError/rejectedValue" ;

	// get the argument to the message
	var xpathMessageArg = "errors/org.springframework.validation.FieldError/arguments/int" ;
 


	// default error message 
	var xpathDefaultMessage = "errors/org.springframework.validation.FieldError/defaultMessage" ;
	
	// iterate over all bind exceptions
	var nodelistBindException = doc.selectNodes(xpathBindException) ;
	var nodeBindException = nodelistBindException.next() ;
	while (nodeBindException!=null) {
		var field = nodeBindException.selectSingleNode(xpathFieldError).getValue() ;
		var rejectedValue = nodeBindException.selectSingleNode(xpathRejectedValue).getValue() ;
		var messageArg = nodeBindException.selectSingleNode(xpathMessageArg).getValue() ;
		var defaultMessage = nodeBindException.selectSingleNode(xpathDefaultMessage).getValue() ;
		var nodelistFieldErrorCodes = nodeBindException.selectNodes(xpathFieldErrorCodes) ;
		var nodeFieldErrorCode  = nodelistFieldErrorCodes.next();
		returnMap[field] = defaultMessage ;
		returnMap.length++ ;
		while (nodeFieldErrorCode!=null) {
		        var fieldErrorCode = nodeFieldErrorCode.getValue() ;
			// find the errors in our .jss dynamic properties
			var message = server.getDynamicProperty(fieldErrorCode, messageArg ) ;
			if ( message != null ) {
				returnMap[field] = message ;
				break ;
			}
			// next errorcode
			nodeFieldErrorCode  = nodelistFieldErrorCodes.next();
		}
	
		// next exception
		nodeBindException = nodelistBindException.next() ;
	}
	
	for (var field in returnMap)
	{
		_LOG.warn('returnMap[\''+field+'\'] = [' + returnMap[field] +']')
	}
	
	return returnMap ;
}


/*
* show the error in the status area and in the error block defined for the field.
*/
function displayError( field, message ) {
	setStatus(message);
	var errBlock = gi2spring.getJSXByName(field + "Error" ) ;
	if ( errBlock != null ) {
		errBlock.setText(message).repaint() ;
	}
}

