package com.androidsdk.snaphy.snaphyandroidsdk.repository;
<%
    /*===================================PURE JAVASCRIPT PART==================================*/

    function capitalizeFirstLetter(string) {

        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    function lowercaseFirstLetter(string) {

        return string.charAt(0).toLowerCase() + string.slice(1);
    }

    //convert javascript to java type
    function convertType(type, model){
        if(type === "string" || type === "any"){
            return "String";
        }
        else if (type === "number") {
            return "double";
        }
        else if (type === "object") {
            return "Map<String,  ? extends Object>"
        }
        else if (type === "boolean") {
            return "Boolean"
        }
        else if(type === "geopoint"){
            return "Map<String, Object>"
        }
        else {

            return capitalizeFirstLetter(checkTypeConversion(type, model));
        }
    }

    //check special type conversion for models with hasAndBelongsToMany relations ..
    function checkTypeConversion(type, model){

        //Convert type for hasAndBelongsToMany type like type CategoryRecipe  = Recipe or Category <--- type remove which belongs to current model. of the repo
        if(model.allDef[type] === undefined){
            //Check by removing the model..
            var patt = new RegExp("^" + capitalizeFirstLetter(model.name) );
            var newType = type.replace(patt, "");

            if(model.allDef[newType] !== undefined){
                //Then add this model to new type..
                type = newType;
            }else{
                //Check by removing the model..
                var patt = new RegExp(capitalizeFirstLetter(model.name) + "$" );
                newType = type.replace(patt, "");
                if(model.allDef[newType] !== undefined){
                    //Then add this model to new type..
                    type = newType;
                }
            }
            return type;
        }else{
            return type;
        }
    }



    //Return if type belongs to like CustomerRecipe or RecipeCustomer
    function checkHasAndBelongsToDataType(type, model){
        var hasAndBelongsToMany = false;
        if(model.allDef[type] === undefined){
            //Check by removing the model..
            var patt = new RegExp("^" + capitalizeFirstLetter(model.name) );
            var newType = type.replace(patt, "");

            if(model.allDef[newType] !== undefined){
                //Then add this model to new type..
                hasAndBelongsToMany = true;
            }else{
                //Check by removing the model..
                var patt = new RegExp(capitalizeFirstLetter(model.name) + "$" );
                newType = type.replace(patt, "");
                if(model.allDef[newType] !== undefined){
                    //Then add this model to new type..
                    hasAndBelongsToMany = true;
                }
            }
            return hasAndBelongsToMany;
        }else{
            hasAndBelongsToMany = false;
            return hasAndBelongsToMany;
        }
    }


    //isInternalArgument function function for finding if an argument is internal or not..
    function  isInternalArgument(argumentObj, argumentName, method){
        var argumentSource = argumentObj.http.source;
        var internalArgument = false;
        //Now check if the argument is the internal argument..
        if(argumentSource === "path"){
            //Now check if the argument does not belongs to related mode data..
            if(method.hasResourceParams){
                var argumentFound = false;
                for(var i=0; i< method.resourceParams.length; i++){
                    var resourceArgObj = method.resourceParams[i];
                    if(resourceArgObj.arg === argumentName){
                        argumentFound = true;
                        break;
                    }
                } //forloop ends
                if(argumentFound){
                    internalArgument = false;
                }else{
                    internalArgument = true;
                }
            }else{
                //Argument is internal argument..
                internalArgument = true;
            }
        } //if path
        return internalArgument;
    }


    //Get new argument name to avoid consfusion.. of mismatching.. of id at server
    var getNewArgumentName = function(argumentsObj){
        var newArg = argumentsObj.arg;
        if(argumentsObj.type === "any"){
            if(argumentsObj.http){
                if(argumentsObj.http.source === "path"){
                    if(argumentsObj.arg === "id"){
                        var oldArgumentName = argumentsObj.arg;
                        newArg = lowercaseFirstLetter(model.restDefinition.name) + "" + capitalizeFirstLetter(oldArgumentName);
                    }
                }
            }
        }
        return newArg;
    };

    var modelName = capitalizeFirstLetter(model.name);

    /*===================================END PURE JAVASCRIPT PART==================================*/


%>


import com.google.common.collect.ImmutableMap;
/*
Replacing with custom Snaphy callback methods
import com.strongloop.android.loopback.callbacks.ListCallback;
import com.strongloop.android.loopback.callbacks.ObjectCallback;
import com.strongloop.android.loopback.callbacks.VoidCallback;
*/
import com.androidsdk.snaphy.snaphyandroidsdk.callbacks.ObjectCallback;
import com.androidsdk.snaphy.snaphyandroidsdk.callbacks.DataListCallback;
import com.androidsdk.snaphy.snaphyandroidsdk.callbacks.VoidCallback;
import com.androidsdk.snaphy.snaphyandroidsdk.list.DataList;
import com.androidsdk.snaphy.snaphyandroidsdk.list.Util;

import com.strongloop.android.remoting.adapters.Adapter;
import com.strongloop.android.remoting.adapters.RestContract;
import com.strongloop.android.remoting.adapters.RestContractItem;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Method;
import android.util.Log;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;

<% if(model.base === "User" || modelName === "User"){ %>
//Replaced by Custom  Repo methods
// import com.strongloop.android.loopback.UserRepository;
import com.strongloop.android.loopback.AccessTokenRepository;
import com.strongloop.android.loopback.AccessToken;
import android.content.SharedPreferences;
import org.json.JSONException;
import android.content.Context;
<% } else { %>
//Replaced by Custom ModelRepository method
//import com.strongloop.android.loopback.ModelRepository;
<% } %>


import org.json.JSONArray;
import org.json.JSONObject;


//Import its models too.
import com.androidsdk.snaphy.snaphyandroidsdk.models.<%- modelName %>;
import android.content.Context;
import com.androidsdk.snaphy.snaphyandroidsdk.db.<%- modelName %>Db;

//Now import model of related models..
<% for(relation in model.relations) { %>
    <% if(model.relations.hasOwnProperty(relation)) {
        if(model.allDef[model.relations[relation].model] !== undefined){
            var relatedModelName = model.relations[relation].model;
            var modelName_ = capitalizeFirstLetter(relatedModelName) ;
    %>
            import com.androidsdk.snaphy.snaphyandroidsdk.models.<%- modelName_ %>;
            import com.androidsdk.snaphy.snaphyandroidsdk.repository.<%- modelName_ %>Repository;
            <% if( model.relations[relation].through) {
                var throughModel = model.relations[relation].through;
            %>
                import com.androidsdk.snaphy.snaphyandroidsdk.models.<%- throughModel %>;
                import com.androidsdk.snaphy.snaphyandroidsdk.repository.<%- throughModel %>Repository;
            <% } %>
        <% } %>
    <% } %>
<% } %>



<% if(model.base === "User" || modelName === "User"){ %>
public class <%- modelName %>Repository extends UserRepository<<%- modelName %>> {
<% } else { %>
public class <%- modelName %>Repository extends ModelRepository<<%- modelName %>> {
<% } %>

    private Context context;
    private String METADATA_DATABASE_NAME_KEY = "snaphy.database.name";
    private static String DATABASE_NAME;

    public <%- modelName %>Repository(){
        super("<%- modelName %>", null, <%- modelName %>.class);

    }


    public Context getContext(){
        return context;
    }


    <% if(model.base === "User" || modelName === "User"){ %>
    		//Create public methods..
    		public <%- modelName %> cachedCurrentUser;
            private Object currentUserId;
            private boolean isCurrentUserIdLoaded;

    		public <%- modelName %> getCachedCurrentUser(){
    			return cachedCurrentUser;
    		}

    		public void setCachedCurrentUser(<%- modelName %> user){
    			cachedCurrentUser = user;
    		}

    		/* public void setCurrentUserId(Object id){
    			super.setCurrentUserId(id);
    		} */

            public void findCurrentUser(final ObjectCallback<<%- modelName %>> callback){
                //Call the onBefore method..
                callback.onBefore();

                if(getCurrentUserId() == null){
                    callback.onSuccess(null);
                    return;
                }

                HashMap<String, Object> hashMap = new HashMap<>();
                this.findById((String)getCurrentUserId(), hashMap, new ObjectCallback<<%- modelName %>>() {
                    @Override
                    public void onSuccess(<%- modelName %> user){
                        cachedCurrentUser = user;
                        callback.onSuccess(user);
                        //Call the finally method..
                        callback.onFinally();
                    }

                    @Override
                    public void onError(Throwable t){
                        callback.onError(t);
                        //Call the finally method..
                        callback.onFinally();
                    }
                });
            }

            public Object getCurrentUserId(){
                if(currentUserId != null){
                  return currentUserId;
                }
                else{
                  String json = getSharedPreferences().getString(PROPERTY_CURRENT_USER_ID, null);
                  if(json == null){
                      return null;
                  }

                  if(json.equals("[null]")){
                      return null;
                  }

                  try{
                      Object id = new JSONArray(json).get(0);
                      return id;
                  }catch(JSONException e){
                      String msg = "Cannot parse user id '" + json + "'";
                      Log.e("Snaphy", msg, e);
                  }
                }
                return null;
            }

            public void setCurrentUserId(Object currentUserId){
                this.currentUserId = currentUserId;
                cachedCurrentUser = null;
                saveCurrentUserId();
            }

            private void saveCurrentUserId(){
                final SharedPreferences.Editor editor = getSharedPreferences().edit();
                final String json = new JSONArray().put(getCurrentUserId()).toString();
                editor.putString(PROPERTY_CURRENT_USER_ID, json);
                editor.commit();
            }


            private SharedPreferences getSharedPreferences() {
                return getApplicationContext().getSharedPreferences(
                    SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
            }




    <% } %>







    public <%- modelName %>Db getDb() {
      return <%- lowercaseFirstLetter(modelName) %>Db;
    }

    public void set<%- modelName %>Db(<%- modelName %>Db <%- lowercaseFirstLetter(modelName) %>Db) {
      this.<%- lowercaseFirstLetter(modelName) %>Db = <%- lowercaseFirstLetter(modelName) %>Db;
    }

    private <%- modelName %>Db <%- lowercaseFirstLetter(modelName) %>Db;



    //Flag to check either to store data locally or not..
    private boolean STORE_LOCALLY = true;

    public boolean isSTORE_LOCALLY() {
      return STORE_LOCALLY;
    }


    public void  persistData(boolean persist){
      STORE_LOCALLY = persist;
    }



    public void reset__db(){
      if(isSTORE_LOCALLY()){
          getDb().reset__db();
      }
    }



    public void addStorage(Context context){
         try{
            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
            DATABASE_NAME = (String) ai.metaData.get(METADATA_DATABASE_NAME_KEY);
         }
         catch (Exception e){
            Log.e("Snaphy", e.toString());
         }
         set<%- modelName %>Db(new <%- modelName %>Db(context, DATABASE_NAME, getRestAdapter()));
         //allow data storage locally..
         persistData(true);
         this.context = context;
    }


    public RestContract createContract() {
    RestContract contract = super.createContract();
    <% model.restDefinition.methods.forEach(function(restMethodObj){
      var patt = new RegExp("^" + model.name + "\\..+");
      var routeMethod = restMethodObj.routes[0].verb.toUpperCase();
      if(routeMethod === "DEL"){
        routeMethod = "DELETE"
      }
      if(routeMethod === "ALL"){
        routeMethod = "POST"
      }

      //Convert path ids name to avoidConfusion..in case of related data name..
      var methodPatt = /^prototype\.\_?\_?/;
      //If method belongsTo a related Type data..
      if(methodPatt.test(restMethodObj.name)){
        //Now check if it accepts any id params..and change the path argument names.. to avoid confusion with server in case of id name..
        if(restMethodObj.accepts){
          restMethodObj.accepts.forEach(function(argumentsObj, index){
            var newArg = getNewArgumentName(argumentsObj);
            //Now replace the path name..
            restMethodObj.routes[0].path = restMethodObj.routes[0].path.replace(":"+ argumentsObj.arg, ":" +newArg);
          });
        }
      }
    %>

    <% if(restMethodObj.fullName
      && patt.test(restMethodObj.fullName)
      && restMethodObj.name !== "createChangeStream"
      && restMethodObj.name !== "login"
      && restMethodObj.name !== "logout"
      && restMethodObj.name !== "save" ){
      var testPlural = /[sS]$/;
    %>

    <% if (testPlural.test(model.name)){ %>

    contract.addItem(new RestContractItem("/" + "<%- capitalizeFirstLetter(model.name) %>"  + "<%- restMethodObj.routes[0].path %>", "<%- routeMethod %>"), "<%- restMethodObj.fullName %>");
    <% } else { %>
    contract.addItem(new RestContractItem("/" + getNameForRestUrl() + "<%- restMethodObj.routes[0].path %>", "<%- routeMethod %>"), "<%- restMethodObj.fullName %>");
    <% } %>

    <% } %>
    <% });%>
    return contract;
    }



//override getNameForRestUrlMethod
    public String  getNameForRestUrl() {
        <%
        var testPlural = /[sS]$/;
        var testO = /[oO]$/;
        if (testPlural.test(model.name)){
        %>
            return "<%- capitalizeFirstLetter(model.name) %>";
        <%
        }else if(testO.test(model.name)){
            %>
                return "<%- capitalizeFirstLetter(model.name) %>s";
            <%
        }
        else{
        %>
            //call super method instead..
            return super.getNameForRestUrl();
        <%
        }
        %>
    }



    <%#{
        "fullName": "Recipe.prototype.__get__customer",
        "name": "prototype.__get__customer",
        "accepts": [{
            "arg": "id",
            "type": "any",
            "required": true,
            "http": {
                "source": "path"
            },
            "description": "PersistedModel id"
        }, {
            "arg": "refresh",
            "type": "boolean",
            "http": {
                "source": "query"
            }
        }],
        "returns": [{
            "arg": "customer",
            "type": "Customer",
            "root": true
        }],
        "errors": [],
        "description": "Fetches belongsTo relation customer.",
        "documented": true,
        "routes": [{
            "path": "/:id/customer",
            "verb": "get"
        }],
        "internal": "Use Recipe.customer() instead."
      } %>




    <%

    var pastMethod = [];
    model.restDefinition.methods.forEach(function(restMethodObj){
        var patt = new RegExp("^" + model.name + "\\..+");

        //check for create defined as its present here two times..


    %>
        <% if(restMethodObj.fullName
            && patt.test(restMethodObj.fullName)
            && restMethodObj.name !== "createChangeStream"
            && restMethodObj.name !== "login"
            && restMethodObj.name !== "logout"
            && restMethodObj.name !== "save"
            ){

            //metch prototype.__
            var initialPatt = /^[0-9A-Za-z\_]+\./;
            var methodPatt = /prototype\.\_?\_?/;
            var staticMethodName = restMethodObj.fullName.replace(initialPatt, "");
            var restMethodName = restMethodObj.fullName.replace(initialPatt, "");
            restMethodName = restMethodName.replace(methodPatt, "");


            var repeat = false;
            if(pastMethod.length){
                for(var i=0; i<pastMethod.length; i++){
                    var method = pastMethod[i];
                    if(method === restMethodName){
                        console.log("REPEATED ", restMethodName);
                        repeat = true;
                        break;
                    }
                }
            }

            if(repeat){
                console.log("repeated return");
                return;
            }

            pastMethod.push(restMethodName);

            console.log("\n");
            //console.log(createDefined);
            console.log(restMethodObj.fullName);
            console.log(restMethodObj.name);

           /* if(restMethodObj.name.toString().trim() === "getPostDetail"){
                console.log(restMethodObj);
            }*/


            var methodString = "public void ";
            methodString = methodString + restMethodName + "( ";
            //ImmutableMap string concatenation..
            //var mapString = "ImmutableMap.of(";
            var hashMapList = [];


            var totalArgument = 0;

            //Now loop through all the required arguments..
            restMethodObj.accepts.forEach(function(requiredArgumentObj, index){
                var type            = requiredArgumentObj.type;
                var argumentName    = requiredArgumentObj.arg;

                //Change argumentName if possible to avoid confusion..
                //Convert path ids name to avoidConfusion..in case of related data name.
                if(methodPatt.test(restMethodObj.name)){
                    argumentName = getNewArgumentName(requiredArgumentObj);

                }


                var hasAndBelongsToType;
                //boolean checking if the type is custom class type like recipe
                var isCustomClass = false;
                var customClassType;
                var isArray = false;
                if(type instanceof Array){
                    hasAndBelongsToType = checkHasAndBelongsToDataType(type[0], model);
                    isArray = true;
                    //check for custom class
                    if(model.allModels[type[0]] !== undefined){
                        var isCustomClass = true;
                        var customClassType = type[0];
                    }
                    type = "DataList<" + convertType(type[0], model) + ">" ;
                }else{
                    hasAndBelongsToType = checkHasAndBelongsToDataType(type, model);
                    type = convertType(type, model);
                    isArray = false;
                    //check for custom class
                    if(model.allModels[type] !== undefined){
                        var isCustomClass = true;
                        var customClassType = type[0];
                        var isArray = false;
                    }

                }

                //Convert type for hasAndBelongsToMany type like type CategoryRecipe  = Recipe or Category <--- type remove which belongs to current model. of the repo
                if(model.allModels[type] === undefined){
                    //Check by removing the model..
                    var patt = new RegExp("^" + capitalizeFirstLetter(model.name) );
                    var newType = type.replace(patt, "");

                    if(model.allModels[newType] !== undefined){
                        //Then add this model to new type..
                        type = newType;
                    }else{
                        //Check by removing the model..
                        var patt = new RegExp(capitalizeFirstLetter(model.name) + "$" );
                        newType = type.replace(patt, "");
                        if(model.allModels[newType] !== undefined){
                            //Then add this model to new type..
                            type = newType;
                        }
                    }
                }




                //Ignore hasAndBelongsToMany
                if(hasAndBelongsToType === false){
                    //If type belongs to hasAndBelongsToMany then ignore the type and argument..
                    //TODO RIGHT NOW I AM IGNORING TYPE LIKE RECIPECATEGORY which belongs to hasAndBelongsTo Many type in future you can add..
                    //Add it later in else..
                    //ImmutableMap of mapping data..

                /*    if(totalArgument === 0){
                        mapString = mapString + '"' + argumentName + '"' +  ', ' + argumentName ;
                    }else{
                        mapString = mapString + ', "' + argumentName + '"' +  ', ' + argumentName ;
                    }
*/

                    //Convert type of argument of it is a custom class type..
                    if(isCustomClass){
                        //Convert custom class to hashMap type first
                        //if array
                        if(isArray){
                            methodString = methodString + " " + "DataList<Map<String,  ? extends Object>>" + " " + argumentName + ", ";

                                //Adding array argument to hash
                                hashMapList.push( "hashMapObject.put(\"" + argumentName + "\", " + argumentName + ");" );
                        }else{
                            methodString = methodString + " " + "Map<String,  ? extends Object>" + " " + argumentName + ", ";
                            //Adding array argument to hash
                            hashMapList.push( "hashMapObject.putAll(" + argumentName + ");" );
                        }
                    }else if(argumentName === "data"){
                        methodString = methodString + " " + type + " " + argumentName + ", ";
                        //and argument source is body..
                        if(requiredArgumentObj.http){
                            if(requiredArgumentObj.http.source === "body"){
                                //THen set putAll in hashMap mathod..
                                //Adding array argument to hash
                                hashMapList.push( "hashMapObject.putAll(" + argumentName + ");" );
                            }else{
                                //Adding array argument to hash
                                hashMapList.push( "hashMapObject.put(\"" + argumentName + "\", " + argumentName + ");" );
                            }
                        }else{
                            //Adding array argument to hash
                            hashMapList.push( "hashMapObject.put(\"" + argumentName + "\", " + argumentName + ");" );
                        }
                    }else{

                        methodString = methodString + " " + type + " " + argumentName + ", ";
                        //Adding array argument to hash
                        hashMapList.push( "hashMapObject.put(\"" + argumentName + "\", " + argumentName + ");" );

                    }


                    //console.log(methodString);
                    /*totalArgument ++;*/
                }

            }); //end of accept argument loop..

            /*//If no argument is required then add null type..
            if(totalArgument !== 0){
                //Wrapup ImmutableMap data..
                mapString  = mapString + ")";
            }else{
                mapString  = "null";
            }*/



            //Now get the return type....
            var callback ;
            var returnType;
            var callbackType;
            //Type name like String etc..
            var type;


            var method = restMethodObj;
            if(method.returns.length && Object.keys(method.returns[0]).length !== 0){
                if(method.returns[0].type instanceof Array){
                    type = convertType(method.returns[0].type[0], model);



                    if(model.allModels[type] !== undefined){
                        returnType = "DataList<" + type + ">";
                        methodString = methodString  +  "final DataListCallback<" + type + "> callback)";
                        callback = "DataListCallback<" + type + "> ";
                        callbackType = "DataListCallback";
                    }else{
                        returnType = type;
                        //methodString = methodString  +  "final Adapter.JsonArrayCallback callback)";
                        methodString = methodString  +  "final ObjectCallback<JSONArray> callback)";

                        callback = "new Adapter.JsonArrayCallback()";
                        callbackType = "DataListCallback";

                    }
                }else{

                    type = convertType(method.returns[0].type, model);
                    if(model.allModels[type] !== undefined){
                        returnType = type;
                        methodString = methodString  +  "final ObjectCallback<" + type + "> callback)";
                        callback = "ObjectCallback<" + type + "> ";
                        callbackType = "ObjectCallback";
                    }else{
                        returnType = type;

                        //methodString = methodString + "final Adapter.JsonObjectCallback  callback )";
                        methodString = methodString + "final ObjectCallback<JSONObject>  callback )";
                        //methodString = methodString  +  "final ObjectCallback<" + type + "> callback)";
                        callback = "new Adapter.JsonObjectCallback()";

                        //callback = "ObjectCallback<" + type + "> ";
                        callbackType = "ObjectCallback";

                    }

                }
            }else{
                methodString = methodString  +  "final VoidCallback callback)";
                callback = "VoidCallback ";
                //returnType = type;
                callbackType = "VoidCallback";
            }

        %>
            //Method <%- restMethodName %> definition
            <%- methodString %>{

                /**
                Call the onBefore event
                */
                callback.onBefore();


                //Definging hashMap for data conversion
                Map<String, Object> hashMapObject = new HashMap<>();
                //Now add the arguments...
                <%
                    hashMapList.forEach(function(hasMapAddMethod){
                %>
                        <%- hasMapAddMethod %>
                <%
                    });
                %>

                <% if(callbackType === "VoidCallback") {%>
                    invokeStaticMethod("<%- staticMethodName %>", hashMapObject, new Adapter.Callback() {
                        @Override
                        public void onError(Throwable t) {
                                callback.onError(t);
                                //Call the finally method..
                                callback.onFinally();
                        }

                        @Override
                        public void onSuccess(String response) {
                            callback.onSuccess();
                            //Call the finally method..
                            callback.onFinally();
                        }
                    });
                <% } %>


                <% if(callbackType === "ObjectCallback") {%>
                    <% if(model.allModels[type] === undefined) { %>
                    invokeStaticMethod("<%- staticMethodName %>", hashMapObject, new Adapter.JsonObjectCallback() {
                    <% } %>
                    <% if(model.allModels[type] !== undefined) { %>
                    invokeStaticMethod("<%- staticMethodName %>", hashMapObject, new Adapter.JsonObjectCallback() {
                    <% } %>
                        @Override
                        public void onError(Throwable t) {
                            callback.onError(t);
                            //Call the finally method..
                            callback.onFinally();
                        }

                        @Override
                        public void onSuccess(JSONObject response) {
                          try{
                            <% if(model.allModels[type] === undefined) { %>
                                callback.onSuccess(response);
                            <% }else{ %>
                                if(response != null){
                                    <%- type %>Repository <%- lowercaseFirstLetter(type) %>Repo = getRestAdapter().createRepository(<%- type %>Repository.class);
                                    if(context != null){
                                        try {
                                            Method method = <%- lowercaseFirstLetter(type) %>Repo.getClass().getMethod("addStorage", Context.class);
                                            method.invoke(<%- lowercaseFirstLetter(type) %>Repo, context);

                                        } catch (Exception e) {
                                            Log.e("Database Error", e.toString());
                                        }

                                        //<%- lowercaseFirstLetter(type) %>Repo.addStorage(context);
                                    }
                                    Map<String, Object> result = Util.fromJson(response);
                                    <%- type %> <%- lowercaseFirstLetter(type) %> = <%- lowercaseFirstLetter(type) %>Repo.createObject(result);

                                      //Add to database if persistent storage required..
                                      if(isSTORE_LOCALLY()){
                                          //http://stackoverflow.com/questions/160970/how-do-i-invoke-a-java-method-when-given-the-method-name-as-a-string
                                          try {
                                                    Method method = <%- lowercaseFirstLetter(type) %>.getClass().getMethod("save__db");
                                                    method.invoke(<%- lowercaseFirstLetter(type) %>);

                                          } catch (Exception e) {
                                            Log.e("Database Error", e.toString());
                                          }

                                      }

                                    callback.onSuccess(<%- lowercaseFirstLetter(type) %>);
                                }else{
                                    callback.onSuccess(null);
                                }
                            <% } %>
                          }catch(Exception e){
                            Log.e("Snaphy", e.toString());
                          }

                            //Call the finally method..
                            callback.onFinally();
                        }
                    });
                <% } %>

                <% if(callbackType === "DataListCallback") {%>
                    invokeStaticMethod("<%- staticMethodName %>", hashMapObject, new Adapter.JsonArrayCallback() {
                        @Override
                        public void onError(Throwable t) {
                            callback.onError(t);
                            //Call the finally method..
                            callback.onFinally();
                        }

                        @Override
                        public void onSuccess(JSONArray response) {
                          try{
                            <% if(model.allModels[type] === undefined) { %>
                            callback.onSuccess(response);
                            <% }else{ %>
                                if(response != null){
                                    //Now converting jsonObject to list
                                    DataList<Map<String, Object>> result = (DataList) Util.fromJson(response);
                                    DataList<<%- type %>> <%- lowercaseFirstLetter(type) %>List = new DataList<<%- type %>>();
                                    <%- type %>Repository <%- lowercaseFirstLetter(type) %>Repo = getRestAdapter().createRepository(<%- type %>Repository.class);
                                    if(context != null){
                                        try {
                                            Method method = <%- lowercaseFirstLetter(type) %>Repo.getClass().getMethod("addStorage", Context.class);
                                            method.invoke(<%- lowercaseFirstLetter(type) %>Repo, context);

                                        } catch (Exception e) {
                                            Log.e("Database Error", e.toString());
                                        }
                                    }
                                    for (Map<String, Object> obj : result) {

                                        <%- type %> <%- lowercaseFirstLetter(type) %> = <%- lowercaseFirstLetter(type) %>Repo.createObject(obj);

                                        //Add to database if persistent storage required..
                                        if(isSTORE_LOCALLY()){
                                            //http://stackoverflow.com/questions/160970/how-do-i-invoke-a-java-method-when-given-the-method-name-as-a-string
                                            try {
                                                      Method method = <%- lowercaseFirstLetter(type) %>.getClass().getMethod("save__db");
                                                      method.invoke(<%- lowercaseFirstLetter(type) %>);

                                            } catch (Exception e) {
                                                Log.e("Database Error", e.toString());
                                            }
                                        }

                                        <%- lowercaseFirstLetter(type) %>List.add(<%- lowercaseFirstLetter(type) %>);
                                    }
                                    callback.onSuccess(<%- lowercaseFirstLetter(type) %>List);
                                }else{
                                    callback.onSuccess(null);
                                }
                            <% } %>
                          }catch(Exception e){
                            Log.e("Snaphy",e.toString());
                          }
                          //Call the finally method..
                          callback.onFinally();
                        }
                    });
                <% } %>

            }//Method <%- restMethodName %> definition ends here..

            <%#
            //EXAMPLE
            //Now add methods for each restMethods..
            public void get__customer(String id, final ObjectCallback<Customer> callback) {
                invokeStaticMethod("prototype.__get__customer", ImmutableMap.of("id", id), new Adapter.JsonObjectCallback() {
                    @Override
                    public void onSuccess(JSONObject response) {
                        try{
                          CustomerRepository responseCustomerRepository = new CustomerRepository();
                          Customer  customer = response != null
                                  ? responseCustomerRepository.createObject(Util.fromJson(response))
                                  : null;
                          //List<Order> customerList ;
                          callback.onSuccess(customer);
                        }catch(Exception e){
                          Log.e("Snaphy", e.toString());
                        }

                    }

                    @Override
                    public void onError(Throwable t) {
                        callback.onError(t);
                    }
                });

            }
            //END EXAMPLE
            %>

        <% } %>
    <% });%>



}
