/*
 *   Depends:
 *	ui.core.js
 */

(function($) {


   function text_exp(exp_str){
     this.inheritFrom = exp;
     this.inheritFrom();
     this.eval = function(data, for_index)
     {
       return exp_str;
     };
   }

   function cycle_exp(exp_str){
     this.inheritFrom = exp;
     this.inheritFrom();
     this.even_text = null;
     this.odd_text = null;
     this.my_cycle_reg = /\[\[\s*cycle\s+(.*?)\s+(.*?)\s*\]\]/;

     this.code_gen = function()
     {
       var regex_r = this.my_cycle_reg.exec(exp_str);
       this.even_text = regex_r[1];
       this.odd_text = regex_r[2];
     };

     this.eval = function(data, for_index)
     {

       if(for_index%2 == 0)
       {
	 // even
	 var r = this.even_text;
       }
       else
       {
	 // odd
	 var r = this.odd_text;
       }
       return r;
     };
   }

   function var_exp(exp_str) {
     this.inheritFrom = exp;
     this.inheritFrom();
     this.key_reg = /\[\=(.*?)\]/;
     this.var_ref_reg = /(.*?)\.(.*)/,

     this.code = null;
//     console.log(exp_str);//xxx
     this.code_gen = function()
     {
       var key_str = exp_str.match(this.key_reg)[1];
     //  var s1 = exp_str.replace(this.var_ref_reg, "$1");
//       var s2 = exp_str.replace(this.var_ref_reg, "$2");
//       console.log("s1: " + s1); //xxx
//       console.log("s2: " + s2); //xxx
       var key_list = key_str.split(".");

       this.code = 'data';

       for(var i = 0 ; i < key_list.length; i++)
       {
	 this.code += '["' + key_list[i] + '"]';
       }
       //this.code = 'data["' + key[1] + '"]';
     };

     this.eval = function(data, for_index)
     {
       var r = eval(this.code);
       if(r == undefined)
	 return "";
       return r;
     };
   }

   function for_exp(exp_str){
//     console.log("for_exp: " + exp_str);//xxx
     this.inheritFrom = exp;
     this.inheritFrom();
     this.content_reg = /^\[\[\s*for.*?\]\](.*?)\[\[\s*endfor\s*\]\]$/;
     this.for_item_reg = /\[\[\s*for\s+(.*?)\s+in\s+(.*?)\]\].*/;

     this.code = null;
     this.code_gen = function()
     {
       var for_regex_r = this.for_item_reg.exec(exp_str);
       var for_item_str = for_regex_r[1].split(" ").join("");
       var for_data_str = for_regex_r[2].split(" ").join("");
       var content_str = this.content_reg.exec(exp_str)[1];

//       console.log("for_item_str: " + for_item_str);//xxx
//       console.log("for_data_str: " + for_data_str);//xxx
//       console.log("content_str: " + content_str);//xxx

       var ex = new exp(content_str);
       ex.code_gen();
       this._children.push(ex);

       //       var r = "";

       this.code =
       "var r = '';"+
       //"alert(data['"+ for_data_str +"']);"+
       "var d = data['"+ for_data_str +"'];"+
       "for(var i = 0 ; i < d.length; i++)"+
       "{"+
	 "var item = d[i];"+
         "var param = {"+for_item_str+":item};"+
	 "for(var key in data)"+
	 "{"+
	   "param[key] = data[key];"+
	 "}"+
         "var children_str = '';"+
         "for(var j =0 ; j < this._children.length; j++)"+
	 "{"+
            "children_str += this._children[j].eval(param, i);"+
	 "}"+
	 "r += children_str;" +
       "}"+
       "r;";

     };

     this.eval = function(data, for_index)
     {
       //console.log(data);//xxx
       //console.log("for eval:" + this.code);//xxx
       var r =  eval(this.code);
       return r;
     };
   }

   function exp(exp_str){
//     this.token_reg = /\[\[\s*for\s+.*?\[\[endfor\]\]|\[\=.*?\]/g,
//     this.token_reg = /\[\[\s*for\s+.*?\]\]|\[\[\s*endfor\s*\]\]|\[\=.*?\]/g,
//     this.for_reg = /\[\[\s*for\s+.*?\[\[endfor\]\]/,
     this.token_reg = /\[\=.*?\]|\[\[\s*for\s+.*?\]\]|\[\[\s*endfor\s*\]\]|\[\[\s*cycle\s+.*?\]\]|[^\[\]]+/g,
     this.for_reg = /\[\[\s*for\s+.*?\]\]/,
     this.end_for_reg = /\[\[\s*endfor\s*\]\]/,
     this.var_reg = /\[\=.*?\]/,
     this.cycle_reg = /\[\[\s*cycle\s+.*?\s*\]\]/,
//     this.token_reg = new RegExp("\[\[\s*for\s+.*?\[\[endfor\]\]|\[\=.*?\]", "g");
//     this.for_reg = new RegExp("\[\[\s*for\s+.*?\[\[endfor\]\]", "g");
//     this.var_reg = new RegExp("\[\=.*?\]", "g");

     this._exp_str = exp_str; //for debugging
     this._children = [];

     this.code_gen = function(){

       var token_list = exp_str.match(this.token_reg);
       var begin_idx, end_idx = 0;
//       console.log(exp_str);
//       console.log(token_list);

       for(var i=0; i < token_list.length; i++)
       {
	 if(this.for_reg.test(token_list[i]))
	 {
	   //need to find endfor.
	   var counter = 1;
	   var for_block_str = token_list[i];
	   for(i+=1; i < token_list.length; i++)
	   {
	     var end_for_candidate_token = token_list[i];
	     if(this.for_reg.test(end_for_candidate_token))
	     {
	       counter++;
	     }
	     else if(this.end_for_reg.test(end_for_candidate_token))
	     {
	       counter--;
	     }
	     for_block_str += end_for_candidate_token;

	     if(counter == 0)
	     {
	       var f_exp = new for_exp(for_block_str);
	       f_exp.code_gen();
	       this._children.push(f_exp);
	       break;
	     }
	   }// for
	 }
	 else if(this.var_reg.test(token_list[i]))
	 {
	   var v_exp = new var_exp(token_list[i]);
	   v_exp.code_gen();
	   this._children.push(v_exp);
	 }
	 else if(this.cycle_reg.test(token_list[i]))
	 {
//	   console.log(">>>>>>>>>>>> a cycle is encountered."); //xxx
	   var c_exp = new cycle_exp(token_list[i]);
//	   console.log(">>>>>>>>>>>> done construction a cycle expression."); //xxx
	   c_exp.code_gen();
	   this._children.push(c_exp);
	 }
	 else
	 {
	   //plain text
	   var t_exp = new text_exp(token_list[i]);
	   this._children.push(t_exp);
	 }

       }// for

     };

     this.eval = function(data, for_index){
       var r = "";
       for(var i =0 ; i < this._children.length; i++)
       {
	 r += this._children[i].eval(data, for_index);
       }
//       console.log("r:" + r);
       return r;
     };
   };

   var KtTemplate ={

     root_exp : null,

     _init:function(){
       var e = new exp(this.options['template']);
       e.code_gen();
       this.root_exp = e;
     },

     render:function(params){
       var r = this.root_exp.eval(params);
       $(this.element).append(r);
     },
     
     renderPrepend:function(params){
       var r = this.root_exp.eval(params);
       $(this.element).prepend(r);
     },

     clear:function(params){
       $(this.element).empty();
     }

   };



   $.widget("kt.ktTemplate", KtTemplate);

 })(jQuery);
