/**
 * Module
 * @author Jae Cho
 * Represents a module that can be embedded in a page.
 *
 * NOTE: in JavaScript, class is hierarchy is established using prototype.
 * Since prototype object is shared by all child objects, note that
 * properties of the prototypes are also shared.
 *                                                             thi
 * ChildModule.prototype = new Module();
 */
 function Module() {

    /** parent page - to be set when module is registered with page */
    this._page = null;

    /** module name: this should be overwritten in the child class
     * when a module is registered in a page, name is used as an ID of the module.
     * Thus make sure the name is unique to a given module.
     * */
    this._name = null;

    /** response object names - to be defined in child class */
    this.resObjectNames = null;

    /** owner of the module */
    this.ownerId = null;

    /** set page object - this needs to be called by page object */
    this.setPage = function(page) {
        this._page = page;
    };

    /** return module name */
    this.getName = function() {
        return this._name;
    };

     /**
      * Make a REST API request. 
      * @param path - path to the resource
      * @param httpMethod - HTTP method: 'POST' or 'GET'
      * @param data - data to be converted to query parameter
      * @param success - callback method
      * @param formId - id of the form for form submission
      */
    this._makeRestRequest = function(path, httpMethod, data, success, formId) {

        var errorHandler = bindContext(this, this._handleError);
        var successHandler = bindContext(this, success);
        var options = {
           url: "/dynamic/rest" + path,
           type: httpMethod,
           dataType: 'json',
           data: data,
           success: successHandler,
           error:  errorHandler
        };

        if (formId){
           $(formId).ajaxSubmit(options);  // Call the Form plugin
        }else if (data){
            $.ajax(options);  // Non-form request
        }
    };

      /**
      * handle field validation errors - this should be implemented by child classes
      * @param field - id of the element to insert error message into
      * @param message - message to insert
      */
     this._handleFieldErrors = function(obj){
//         console.log("module._handleFieldErrors called");
     };

      /**
      * handle general errors - this should be implemented by child classes
      * @param message - message to insert; the DOM element should be defined in the child classes
      */
     this._handleGeneralErrors = function(obj){
//         console.log("module._handleGeneralErrors called");
     };

    this._handleError = function(xhr) {
//        console.log("Module._handleError called");

        if (xhr.responseText){
            try{
                var errObj = JSON.parse(xhr.responseText);

                if (errObj.returnCode == "ValidationError") {
                    if (errObj.fieldErrors){
                          this._handleFieldErrors(errObj.fieldErrors);
                    }
                    if (errObj.generalErrors){
                          this._handleGeneralErrors(errObj.generalErrors);
                    }
                    return;
                }
           
            }catch(err){
//                    this._handleError( { Message: "Unknown server error." });
            }
        }
        this._showGeneralError(xhr);
    };

     this._showGeneralError = function(xhr) {

         var title = null;

         switch (xhr.status) {
         case 401:
             title = "You do not have the rights for this action.";
         break;
         case 403:
            title = "You have performed a forbidden action.";
         break;
         case 404:
             title = "The page you requested was not found.";
         break;
         case 500:
            title = "The server encountered an internal error.";
         break;
         case 503:
             title = "The service is unavailable.";
         break;
         default:
            title = "An error has occurred.";
         }

         this._page.displayError(title);
     }


    /** initialize the module. child modules should imlement this method to
     * intiialize UI state and bind actions to elements.
     */
    this.initialize = function() {
    };

    /** list of initial AJAX request that needs to be made when a module loads */
    this.getInitRequests = function() {
        return [];
    };

    /** list of AJAX request that should be called to update the module upon login/logout
     * some pages refreshes themselves upon login state change
     * some pages can handle login/logout more 'gracefully' by simply iterating through its modules
     * calling this method. Modules that need to be updated w/o page refresh should implement this method
     */
     this.updateAndGetLoginChangeRequests = function() {
        return [];
     };


    /** handle array of response object - this is to be defined by child class
     * @name name of parameter
     * @value list of response objects
     */
    this.handleResObjects = function(resObjects) { };

    /** @return list of request actions that can be handled by this module */
    this.getPageActionNames = function() {
        return [];
    };

    /** handle request action
    * @action name of action to invoke
    * @params bean containing request parameters
    *
    * */
    this.handlePageAction = function(action, params) { };

    this.isViewedBySelf = function() {
        var uid = this._page.getLoggedInUserId();
        if (uid && uid == this.ownerId) {
            return true;
        }
        return false;
    };
}