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

(function($) {
   function KtTableHandler(element, options){
     this.element = element;
     this.options = options;
     this.tab = undefined;
     this.page = undefined;
     this.table_id = undefined;
     this.root_url = undefined;
     this.data = undefined;
     this.sort_dict = {}; // true means ascending; false means descending.
     this.type_dict = {}; // int, float, or string
   };

   KtTableHandler.prototype = {
    _trigger_load_table_data : function(){
       var is_a_member_of_a_subtab_chart = this._is_a_member_of_a_subtab_chart();
       if(is_a_member_of_a_subtab_chart){
	 var table_id = '#t'+this.table_id.split("_")[0];
	 var table_widget_ids = $(table_id).ktSubTabTableRefactored("option", "table_widget_ids");
	 var target_table_ids = [];
	 for(var i = 0; i< table_widget_ids.length; i++){
	   $(document).trigger('load_all_table_data', [table_widget_ids[i]['index']]);
	 }
       }else{
	 $(document).trigger('load_all_table_data', [this.table_id]);
       }
     },

     _delete_row_handler : function (dom){
       var arg = this._delete_row_handler_get_ajax_args(dom);
       var _this_obj = this;
       $.ajax(
	 {
	   type: "GET",
	   url : "/dashboard/filter/ajax_create_filter/",
	   data: arg,
	   success: function(msg){
	     // If this chart is embedded in a subtype table, we will need to
	     // figure out the other tab charts and update those as well.
	     // Otherwise, update this chart only.
	     _this_obj._trigger_load_table_data();
	   },
	   error: function(msg){
	     var str = "A filter for this row already exists. Enable it?";
	     Boxy.confirm(str,
			  function ()
			  {
			    $.ajax(
			      {
				type: "GET",
				url : "/dashboard/filter/ajax_toggle_filter_without_id/",
				data: arg,
				success: function(msg){
				  // If this chart is embedded in a subtype table, we will need to
				  // figure out the other tab charts and update those as well.
				  // Otherwise, update this chart only.
				  _this_obj._trigger_load_table_data();
				}
			      } );
			  });
	   }
	 }); // $.ajax
     },

     _delete_row_handler_get_ajax_args : function(dom){
       var this_row = $(dom).parent().parent();
       var channel_type = $(dom).attr('channel_type');
       var arg = {channel_type : channel_type};
       arg['st1'] = $($(this_row).children()[2]).text(); // category
       arg['st2'] = $($(this_row).children()[1]).text(); // campaign
       arg['st3'] = $($(this_row).children()[3]).text(); // content
       return arg;
     },

     _bind_table_events : function(){
       var $remove_btns = $("#"+ this.table_id +"_table a.remove_btn");
       var this_obj = this;
       if($remove_btns.length > 0){
	 $remove_btns.click(function(event){
			      this_obj._delete_row_handler(event.target);
			    });
       }
     },

     _is_a_member_of_a_subtab_chart : function(){
       var tmp_lst = this.table_id.split("_");
       var size = tmp_lst.length;
       if( tmp_lst[size-1] == 'tab'){
	 return true;
       }
       return false;
     },

     _get_table_j : function(){
       var my_id = $(this.element).attr('id');
       return $("#"+my_id+"_table");
     },

     _get_table_header : function(show_frame){
       if(show_frame == true)
       {
            var template_str =
            "<div id='[=table_id]_secondary_data' class='k-box-secondary'></div>\
            <div class='k-box'> \
                <div class='k-box-head'> \
                    <div class='k-box-head-info'>\
                        <h1>[=title]</h1> \
                        <a href='#' index='[=index]' class='help' title='[=bubble_text]'>help</a> \
                        <a href='#' class='export' id='[=data_export_id]'>Export</a>\
                    </div> \
                </div>\
                <div class='k-box-body'> \
                     <table class='k-table' id='[=table_id]_table' \
                        cellpadding=\"0\" cellspacing=\"0\" border=\"0\"  id=\"data\" style=\"width: 100%\"> \
                        <tr class=\"head-tr left-border\"> \
                            <td decimal='[=first_coln.coln_decimal]' class='lit first-coln [=first_coln.coln_type] [=first_coln.coln_class]' coln_id='[=first_coln.coln_id]' width='[=first_coln.coln_width]'><h5>[=first_coln.coln_name]</h5></td>\
                            [[for coln in coln_list]] \
                            <td decimal='[=coln.coln_decimal]' class='lit [=coln.coln_type] [=coln.coln_class]' coln_id='[=coln.coln_id]' width='[=coln.coln_width]'><h5>[=coln.coln_name]</h5></td>\
                            [[endfor]]\
                        </tr>\
                    </table>\
                </div>\
            </div>";
       }
       else
       {
            var template_str =
            "<div id='[=table_id]_secondary_data' style='display:none;'></div>\
            <div> \
                 <table class='k-table' id='[=table_id]_table' \
                cellpadding=\"0\" cellspacing=\"0\" border=\"0\"  id=\"data\" style=\"width: 100%\"> \
                    <tr class=\"head-tr left-border\"> \
                        <td decimal='[=first_coln.coln_decimal]' class='lit first-coln [=first_coln.coln_type] [=first_coln.coln_class]' coln_id='[=first_coln.coln_id]' width='[=first_coln.coln_width]'><h5>[=first_coln.coln_name]</h5></td>\
                        [[for coln in coln_list]] \
                        <td decimal='[=coln.coln_decimal]' class='lit [=coln.coln_type] [=coln.coln_class]' coln_id='[=coln.coln_id]' width='[=coln.coln_width]'><h5>[=coln.coln_name]</h5></td>\
                        [[endfor]]\
                    </tr>\
                </table>\
            </div>";
        }
        return template_str;
     },

     _construct_coln_header : function(show_frame){
       var my_id = $(this.element).attr('id');
       var template_str = null;
       var data_export_id = "data_export_"+ this.table_id;

       var coln_count = this.options['coln'].length;
       var first_coln = undefined;
       var remainder_coln_array = [];
       var colns_from_option = this.options['coln'];
       var idx = 0;
       for(var i = 0; i < coln_count; i++)
       {
	 if(i==0)
	   first_coln = colns_from_option[i];
	 else
	 {
	   remainder_coln_array[idx] = colns_from_option[i];
	   idx++;
	 }
       }

       var params = {
	 title          : this.options['title'],
	 my_id          : my_id,
	 first_coln     : first_coln,
	 coln_list      : remainder_coln_array,
	 table_id       : this.table_id,
	 bubble_text    : this.options['bubble_text'],
	 index          : this.options['index'],
	 data_export_id : data_export_id
       };


       if(this.options['subtab'] != undefined)
       {
	 params['subtab'] = this.options['subtab'];
       }


       template_str = this._get_table_header(show_frame);

       if(show_frame)
	 params['data_export_id'] = data_export_id;

       $(this.element).ktTemplate(
	 {
	   template: template_str
	 }
       );

       $(this.element).ktTemplate('render', params);

       this._build_load_table_notification();
       //setup sort_dict
       var coln_list = this.options['coln'];
       var len = coln_list.length;
       for(var i =0; i < len; i++)
       {
	 var coln = coln_list[i];
	 this.sort_dict[coln.coln_id] = true;
	 this.type_dict[coln.coln_id] = coln.coln_type;
       }
     },

     _setup_rows_template : function(rows) {
       $("#"+this.table_id+"_table").ktTemplate(
	 {
	   template:
	   '[[for item in list]]'+ rows + '[[endfor]]'
	 }
       );
     },

     _setup_sorting : function(){
       // make title headers clickable
       var _this_obj = this;
       $(this._gen_table_id() + " td.lit").click(
	 function(){
 	   var id = $(this).attr('coln_id');
 	   _this_obj._sort(id, _this_obj.data);
	   _this_obj._bind_table_events();
 	 }
       );
     },

     _gen_table_id : function(){
       return "#"+this.table_id+"_table";
     },

     _clear_content : function(){
       var rows = $(this._gen_table_id()).children().children();
       var len = rows.length;

       // purposedly skip the title row
       for(var i = 1; i < len; i++)
       {
	 $(rows[i]).remove();
       }

     },

     _dollarize: function(value){
       if(value !="N/A" && value != "--")
       {
	 return "$"+value;
       }
       return value;
     },

     _seconds_to_hms : function(secs){
       if(secs != "N/A" && secs != "--")
       {
	 var remaining_secs = Math.floor(secs);
	 if(remaining_secs == 0)
	   return "00:00:00";
	 var hr = Math.floor(remaining_secs/3600);
	 remaining_secs -= hr*3600;
	 hr += "";
	 if(hr.length == 1)
	   hr = "0"+hr;

	 var min = Math.floor(remaining_secs/60);
	 remaining_secs -= min*60;
	 min += "";
	 if(min.length == 1)
	   min = "0"+min;

	 var sec = remaining_secs;
	 sec += "";
	 if(sec.length == 1)
	   sec = "0"+sec;

	 var r = hr + ":" + min + ":" + sec;
	 return r;
       }else{
	 return secs;
       }
     },

     _sort_comp_ascending_float: function(a,b, coln_id){
       var a_v = parseFloat(a[coln_id]);
       var b_v = parseFloat(b[coln_id]);
       if(isNaN(a_v) && isNaN(b_v))
	 return 0;
       if(isNaN(a_v))
	 return -1 - b_v;
       if(isNaN(b_v))
	 return a_v - -1;
       return a_v - b_v;
     },

     _sort_comp_descending_float: function(a,b,coln_id){
       var a_v = parseFloat(a[coln_id]);
       var b_v = parseFloat(b[coln_id]);
       if(isNaN(b_v) && isNaN(a_v))
       	 return 0;
       if(isNaN(b_v))
	 return -1 - a_v;
       if(isNaN(a_v))
	 return b_v - (-1);
       return b_v - a_v;
     },

     _format_data : function(data){
       var r = [];
       var len = data.length;

       var tmp_data = data[0];
       for(var row = 0; row < len; row++)
       {
	 r[row] = {};
       }

       for(var key in tmp_data)
       {
	 var script_str = "";
	 var type = this.type_dict[key];
	 if((typeof tmp_data[key]) == 'number')
	 {
	   // // format the decimal places first

	   var decimal_places_str = $(this._gen_table_id() + " td[coln_id='"+key+"']").attr('decimal');

	   script_str += "val = parseFloat(val);";
	   if(type == "percentage")
	   {

	     script_str += "val = val*100.0;";
	   }

	   if(decimal_places_str != "" && decimal_places_str != undefined)
	   {
	     var decimal_places = parseInt(decimal_places_str) ;

	     script_str += "val = this.num_formatter.format_decimal(val, " + decimal_places + ");";
	   }
	   // don't add commas to seconds; otherwise, _seconds_to_hms will break
	   if(type!='time')

	     script_str +="val = this.num_formatter.comma_format(val);";
	 }
	 else
	 {
	   script_str += "val;";
	 }

	 if(type == "percentage")
	 {

	   script_str += "val+='%';";
	 }
	 else if(type == "dollar")
	 {

	   script_str += "val = this._dollarize(val);";
	 }
	 else if(type == "time")
	 {

	   script_str += "val = this._seconds_to_hms(val);";
	 }

	 for(row = 0; row < len; row ++)
	 {
	   var val = data[row][key];
	   r[row][key] = eval(script_str);
	 }
       }

       return r;
     },

     _sort_impl : function(coln_id, data){
       var this_td = $(this._gen_table_id() + " td[coln_id=" + coln_id + "]");
       var this_obj = this;
       var ascending = this.sort_dict[coln_id];
       var type = this.type_dict[coln_id];
       var og_height = this_td.height();
       if(ascending == true) {
         this_td.children("h5").removeClass('sort_ascending').addClass('sort_ascending');
         // clear all the other columns
	 this_td.siblings().children("h5").removeClass('sort_descending').removeClass('sort_ascending');
       }
       else {
         this_td.children("h5").removeClass('sort_ascending').addClass('sort_descending');
	 // clear all the other columns
         this_td.siblings().children("h5").removeClass('sort_descending').removeClass('sort_ascending');
       }
       this_td.height(og_height);

       if(type == "int")
       {
	 if(ascending == true)
	 {
	   data.sort(function(a,b){
		       var a_v = parseInt(a[coln_id]);
		       var b_v = parseInt(b[coln_id]);
		       if(isNaN(a_v))
			 return -1;
		       if(isNaN(b_v))
			 return a_v;
		       return a_v - b_v;
		     });
	 }
	 else
	 {
	   data.sort(function(a,b){
		       var a_v = parseInt(a[coln_id]);
		       var b_v = parseInt(b[coln_id]);
		       if(isNaN(b_v))
			 return -1;
		       if(isNaN(a_v))
			 return b_v;
		       return b_v - a_v;
		     });
	 }
       }
       else if(type == "float" || type == "percentage" || type=="dollar")
       {
	 if(ascending == true)
	 {

	   data.sort(function(a,b){

		       return this_obj._sort_comp_ascending_float(a,b,coln_id);
		     });
	 }
	 else
	 {

	   data.sort(function(a,b){

		       return this_obj._sort_comp_descending_float(a,b,coln_id);
		     });
	 }
       }
       else if(type == "time")
       {
	 if(ascending == true)
	 {
	   data.sort(function(a,b){
		       return this_obj._sort_comp_ascending_float(a,b,coln_id);
		     });
	 }
	 else
	 {
	   data.sort(function(a,b){
		       return this_obj._sort_comp_descending_float(a,b,coln_id);
		     });
	 }
       }
       else if(type == "string")
       {
	 if(ascending == true)
	 {
	   data.sort(function(a,b){
		       if(a[coln_id]> b[coln_id])
			 return 1;
		       else
			 return -1;
		     });
	 }
	 else
	 {
	   data.sort(function(a,b){
		       if(b[coln_id] > a[coln_id])
			 return 1;
		       else
			 return -1;
		     });
	 }
       }
     },

     _sort : function(coln_id, data){
       //do some bookkeeping first
       this.sort_dict[coln_id] = !this.sort_dict[coln_id];
       this._sort_impl(coln_id, data);
       if (data.length == 0) {
            // If there is no data don't need to clear data
            return;
        }
       // repopulate data
       this._clear_content();
       var formated_data = this._format_data(data);
       $(this._gen_table_id()).ktTemplate('render', {
					    list: formated_data
					  });
     },

     _build_empty_table_notification : function() {
        var cell = jQuery("<td>There is no data to display</td>");
        cell.css("text-align","center").css("padding","8px");
        cell.attr("colspan",this.options['coln'].length);
        var row = jQuery("<tr></tr>").append(cell);
        $("#"+this.table_id+"_table").find("tbody").append(row);
     },

     _build_load_table_notification : function() {
        var img = jQuery("<img src=\""+ kt_media_url + "/images/indicator.gif\"/>");
        img.css("padding","5px");
        var cell = jQuery("<td>Loading Data </td>").append(img);
        cell.css("text-align","center").css("padding","8px");
        cell.attr("colspan",this.options['coln'].length);
        var row = jQuery("<tr class=\"loading-row\"></tr>").append(cell);
        $("#"+this.table_id+"_table").find("tbody").append(row);
     },

     _ajax_load_all_table_data_handler : function(data){
       $("#"+this.table_id+"_table").find(".loading-row").remove();
       this.data = data;

        if (data.length == 0) {
            this._build_empty_table_notification();
            return;
        }

       for(var i in this.data) {
         this.data[i]['row_id'] = i;
       }

       $("#"+this.table_id+"_table").ktTemplate('render', {
            list: this._format_data(data)
       });

       this._bind_table_events();
     },

     _export_handler : function(){
       var data_export_url = this.root_url + '/np_data_export/' + this.tab + '/' + this.page + '/' + this.table_id + '/?t=j';
       document.location = data_export_url;
       return false;
     },

     _load_all_table_data_handler : function(){
       var _this_obj = this;
       _this_obj._clear_content(); //clear out the old content.
       this._build_load_table_notification();
       $.ajax(
 	 {
 	   type : 'GET',
 	   url  : _this_obj.root_url + '/np_ajax/' + _this_obj.tab + '/' + _this_obj.page +'/' + _this_obj.table_id +'/?t=j',
 	   dataType: 'json',
 	   success : function(data, textStatus){
	     if( data['__primary_data__'] !=undefined )
	     {
	       _this_obj._ajax_load_all_table_data_handler(data['__primary_data__']);

	       if(data['__secondary_data__'] !=undefined)
	       {
		 $("#"+_this_obj.table_id+"_secondary_data").text(data['__secondary_data__']);
	       }
	       else
	       {
		 $("#"+_this_obj.table_id+"_secondary_data").css("display", "none");
	       }
	       $(document).trigger("onload_all_table_data", [_this_obj.table_id]);
	     }
	     else
	     {
	       $("#"+_this_obj.table_id+"_secondary_data").css("display", "none");
	       _this_obj._ajax_load_all_table_data_handler(data);
	     }
	   }//sucess
 	 }
       );
     },

     init_impl:function() {
       this.tab = this.options['tab'];
       this.page = this.options['page'];
       this.table_id = this.options['index'];
       this.root_url = this.options['root_url'];
       this.num_formatter = new NumFormatter();

       if (this.options['no_table_frame'])
	 if (this.options['no_table_frame'] == true)
	   this._construct_coln_header(false);
	 else
	   this._construct_coln_header(true);
       else
	  this._construct_coln_header(true);

       this._setup_rows_template(this.options['rows']);


       var tab = this.tab;
       var page = this.page;
       var table_id = this.table_id;
       var root_url = this.root_url;

       var _this_obj = this;

       // make title headers clickable
       this._setup_sorting();

       $(document).bind('load_all_table_data', function(event, msg){
			  if(msg == undefined ||
			     msg == _this_obj.table_id)
			  {
			    _this_obj._load_all_table_data_handler();
			  }// if(msg == ...
 			});

       // bind data export link

       var data_export_id = "data_export_" + this.table_id;
       $("#" + data_export_id).click(
	 function()
	 {
	   _this_obj._export_handler();
	   return false;
	 }
       );

       // jQuery(this.element).data('kt_table_handler', this);

     }


   };


   function KtTable()
   {
     this.handler = null;
   }

   KtTable.prototype = {
     _init : function()
     {
       this.handler = new KtTableHandler(this.element, this.options);
       this.handler.init_impl();
     },
     get_handler : function()
     {
       return this.handler;
     }
   };

   ///////////////////// KtNotPermittedTable ////////////////////////

   function KtNotPermittedTableHandler(element, options){
     this.inheritedFrom = KtTableHandler;
     this.inheritedFrom(element, options);
   };

   KtNotPermittedTableHandler.prototype = new KtTableHandler();

   KtNotPermittedTableHandler.prototype._construct_coln_header = function(show_frame){
       var my_id = $(this.element).attr('id');
       var template_str = null;

       var coln_count = this.options['coln'].length;
       var first_coln = undefined;
       var remainder_coln_array = [];
       var colns_from_option = this.options['coln'];
       var idx = 0;
       for(var i = 0; i < coln_count; i++)
       {
         if(i==0)
           first_coln = colns_from_option[i];
         else
         {
           remainder_coln_array[idx] = colns_from_option[i];
           idx++;
         }
       }

       var params = {
         title          : this.options['title'],
         my_id          : my_id,
         first_coln     : first_coln,
         coln_list      : remainder_coln_array,
         table_id       : this.table_id,
         index          : this.options['index']
       };


       if(this.options['subtab'] != undefined)
       {
         params['subtab'] = this.options['subtab'];
       }

       template_str = this._get_table_header(show_frame);
       $(this.element).ktTemplate(
         {
           template: template_str
         }
       );

       $(this.element).ktTemplate('render', params);

     };

     KtNotPermittedTableHandler.prototype._export_handler = function(){
       return false;
     };

     KtNotPermittedTableHandler.prototype._load_all_table_data_handler = function(){
        $("#"+this.table_id+"_table").append(this.row_str);
     };

     KtNotPermittedTableHandler.prototype.init_impl = function() {
       this.tab = this.options['tab'];
       this.page = this.options['page'];
       this.table_id = this.options['index'];
       this.row_str = this.options['rows'];

       if (this.options['no_table_frame'])
         if (this.options['no_table_frame'] == true)
           this._construct_coln_header(false);
         else
           this._construct_coln_header(true);
       else
         this._construct_coln_header(true);

       var tab = this.tab;
       var page = this.page;
       var table_id = this.table_id;
       var root_url = this.root_url;

       var _this_obj = this;

       $(document).bind('load_all_table_data', function(event, msg){
              if(msg == undefined ||
                 msg == _this_obj.table_id)
              {
                _this_obj._load_all_table_data_handler();
              }
             });
     };


   function KtNotPermittedTable()
   {
     this.inheritedFrom = KtTable;
   }

   KtNotPermittedTable.prototype = new KtTable();
   KtNotPermittedTable.prototype._init = function()
   {
     this.handler = new KtNotPermittedTableHandler(this.element, this.options);
     this.handler.init_impl();
   };

   //////////////////////// KtSt1St2Table ///////////////////////////

   function KtSt1St2TableHandler(element, options){
     this.inheritedFrom = KtTableHandler;
     this.inheritedFrom(element, options);
     this.row_click_state = {}; //true: expanded false: folded
     this.st2_data = {};
     this.st3_data = {};
   };

   KtSt1St2TableHandler.prototype = new KtTableHandler();
   KtSt1St2TableHandler.prototype.init_impl = function()
   {
     // call parent's method
     KtTableHandler.prototype.init_impl.call(this);
     var _this_obj = this;
     $(document).bind('toggle_st2st3',
		      function(event, table_id, st1, st2, st3){
			_this_obj._toggle_or_removefilter_st2st3_handler(event, table_id,
								   st1,st2,st3,
								   false);
		      }
		     );
     $(document).bind('delete_st2st3',
		      function(event, table_id, st1, st2, st3){
			_this_obj._toggle_or_removefilter_st2st3_handler(event, table_id,
								   st1,st2,st3,
								   true);
		      }
		     );
   };

   // if force_delete is false, toggles.
   // if force_delete is true, remove it for good.
   KtSt1St2TableHandler.prototype._toggle_or_removefilter_st2st3_handler = function(event, table_id, st1, st2, st3, force_delete)
   {
     if(this.table_id == table_id){
       if(st2 != "*" && st3 == "*" && this.st2_data[st1] != undefined){
	 var st2_data_lst = this.st2_data[st1];
	 var len = st2_data_lst.length;
	 for(var i = 0; i< len; i++){
	   if(st2_data_lst[i]['subtype2'] == st2){
	     if(force_delete)
	       st2_data_lst[i]['deleted'] = false;
	     else
	       st2_data_lst[i]['deleted'] = !st2_data_lst[i]['deleted'];
	     this._populate_cached_st2_row(st1);
	     break;
	   }
	 }// for
       }else if(st2 != "*" && st3 != "*" &&
		this.st3_data[st1] != undefined &&
		this.st3_data[st1][st2] != undefined){
	 var st3_data_lst = this.st3_data[st1][st2];
	 var len = st3_data_lst.length;
	 for(var i = 0; i< len; i++){
	   if(st3_data_lst[i]['subtype3'] == st3){
	     if(force_delete)
	       st3_data_lst[i]['deleted'] = false;
	     else
	       st3_data_lst[i]['deleted'] = !st3_data_lst[i]['deleted'];
	     this._populate_cached_st3_row(st1, st2);
	   }
	   break;
	 }// for
       }
     }
   };

   KtSt1St2TableHandler.prototype._sort = function(coln_id, data)
   {
     // sort st1 level data
     KtTableHandler.prototype._sort.call(this, coln_id, data);
     // sort st2 level data
     var st1_key = null;
     for(st1_key in this.st2_data)
     {
       this._sort_impl(coln_id, this.st2_data[st1_key]);
     }
     // sort st3 level data
     for(st1_key in this.st3_data)
     {
       for(var st2_key in this.st3_data[st1_key])
       {
	 this._sort_impl(coln_id, this.st3_data[st1_key][st2_key]);
       }
     }
     //this._bind_table_events();
     this._repopulate_after_bind_table_events(data);
   };

   KtSt1St2TableHandler.prototype._repopulate_after_bind_table_events = function(data)
   {
     this._populate_all_cached_st2_rows();
     this._populate_all_cached_st3_rows();
     this._show_or_hide_all();
     this._get_rid_of_st1_arrows(data);
     for(st1_key in this.st2_data)
     {
       this._get_rid_of_st2_arrows(this.st2_data[st1_key], st1_key);
     }
   };

   KtSt1St2TableHandler.prototype._get_rid_of_arrows_helper = function(img_lst, data)
   {
     var len = data.length;
     for(var i = 0; i < len; i++)
     {
       if(data[i]['expandable'] == false)
       {
	 $(img_lst[i]).css('visibility', 'hidden');
	 $(img_lst[i]).parent().parent().css('cursor', 'default');
       }
     }
   };

   KtSt1St2TableHandler.prototype._get_rid_of_st1_arrows = function(data)
   {
     var img_lst = $("#"+this.table_id+"_table img.st1_plus");
     this._get_rid_of_arrows_helper(img_lst, data);
   };

   KtSt1St2TableHandler.prototype._get_rid_of_st2_arrows = function(data, st1_str)
   {
     var img_lst = $("#"+this.table_id+"_table img[subtype1="+st1_str+"]");
     this._get_rid_of_arrows_helper(img_lst, data);
   };

   KtSt1St2TableHandler.prototype._ajax_load_all_table_data_handler = function(data)
   {
     KtTableHandler.prototype._ajax_load_all_table_data_handler.call(this, data);
     this._repopulate_after_bind_table_events(data);
   };

   KtSt1St2TableHandler.prototype._save_st3_data = function(subtype1, subtype2, data)
   {
     if(this.st3_data[subtype1] == undefined)
     {
       this.st3_data[subtype1] = {};
     }
     this.st3_data[subtype1][subtype2] = data;
   };

   KtSt1St2TableHandler.prototype._get_undeleted_st2_data = function(st1){
     var r = [];
     var st2_data = this.st2_data[st1];
     var len = st2_data.length;
     for(var i = 0; i < st2_data.length; i++){
       if(st2_data[i]['deleted'] == undefined || st2_data[i]['deleted'] == false){
	 r.push(st2_data[i]);
       }
     }
     return r;
   };
   KtSt1St2TableHandler.prototype._get_undeleted_st3_data = function(st1, st2){
     var r =[];
     var st3_data = this.st3_data[st1][st2];
     var len = st3_data.length;
     for(var i = 0; i < st3_data.length; i++){
       if(st3_data[i]['deleted'] == undefined || st3_data[i]['deleted'] == false){
	 r.push(st3_data[i]);
       }
     }
     return r;
   };

   KtSt1St2TableHandler.prototype._populate_cached_st2_row = function(subtype1)
   {
     var st2_data = this._get_undeleted_st2_data(subtype1);

     var $row = $('tr[table_id=' + this.table_id + '][subtype1='+subtype1+']');
     $row.after("<div></div>"); // add a temporary div
     $($row.next()).ktTemplate(
       {
	 template:
	   '[[ for item in list ]]'+ this.options['st2_rows'] +'[[ endfor ]]'
       }
     );
     $($row.next()).ktTemplate('render', {'list': this._format_data(st2_data),
					  'subtype1': subtype1
					 });

     var subtype2_rows = $row.next().children();
     $row.next().remove();
     $row.after(subtype2_rows);

     //iterate thru all the st2 rows and bind a click event handler
     var $curr_dom = $row.next();
     while($curr_dom.length!=0 && $($curr_dom).attr('class') != 'st1_row')
     {
       var this_obj = this;
       $curr_dom.click(function(event){
			 var $og_target = $(event.target);
			 if($og_target.hasClass('remove_btn')){
			   this_obj._delete_row_handler(event.target);
			 }else{
			   var $row = $(this);
			   if( $row.attr('expandable') == 'true' )
			   {
			     var subtype2 = $($row.children()[1]).text();

			     var need_to_fetch_data = false;
			     if(this_obj.row_click_state[subtype1][1][subtype2] == undefined)
			     {
			       this_obj.row_click_state[subtype1][1][subtype2] = true;
			       need_to_fetch_data = true;
			     }
			     else
			     {
			       //toggle;
			       this_obj.row_click_state[subtype1][1][subtype2] = !this_obj.row_click_state[subtype1][1][subtype2];
			     }

			     if(need_to_fetch_data)
			     {
			       $row.find('img.plus').hide();
			       $row.find('img.loading').show();
			       var url = this_obj.options['root_url'] + '/np_ajax/' + this_obj.options['tab'] + "/" + this_obj.options['page'] + "/" + this_obj.table_id + '/?t=j&fcsst1=' + encodeURIComponent(subtype1) + '&fcsst2='+ encodeURIComponent(subtype2) +'&groupby=' + encodeURIComponent(subtype1);
			       $.ajax(
				 {
				   type : 'GET',
				   url  : url,
				   dataType : 'json',
				   success : function(data, textStatus){
				     this_obj._save_st3_data(subtype1, subtype2, data);
				     this_obj._populate_cached_st3_row(subtype1, subtype2);
				     this_obj._show_or_hide_st3_row(subtype1, subtype2);
				     $row.find('img.loading').hide();
				   }
				 }
			       );//$.ajax
			     }
			     else
			     {
			       this_obj._show_or_hide_st3_row(subtype1, subtype2);
			     }
			   }
			 }
		       });
       $curr_dom = $curr_dom.next();
     }
   };
   KtSt1St2TableHandler.prototype._populate_cached_st3_row = function(subtype1,subtype2)
   {
//     var st3_data = this.st3_data[subtype1][subtype2];
     var st3_data = this._get_undeleted_st3_data(subtype1, subtype2);
     var $row = $('tr[table_id=' + this.table_id + '][subtype1='+subtype1+'][subtype2='+subtype2+'][class="st2_row"]');
     $row.after("<div></div>"); // add a temporary div
     $($row.next()).ktTemplate(
       {
	 template:
	 '[[ for item in list ]]'+ this.options['st3_rows'] +'[[ endfor ]]'
       }
     );
     $($row.next()).ktTemplate('render', {'list': this._format_data(st3_data),
					  'subtype1': subtype1,
					  'subtype2': subtype2
					 });
     var subtype3_rows = $row.next().children();

     $row.next().remove();
     $row.after(subtype3_rows);

     var $curr_dom = $row.next();
     var this_obj = this;
     while($curr_dom.length!=0 && $($curr_dom).attr('class') != 'st1_row' && $($curr_dom).attr('class') != 'st2_row'){
       $curr_dom.click(function(event){
			 var $og_target = $(event.target);
			 if($og_target.hasClass('remove_btn')){
			   this_obj._delete_row_handler(event.target);
			 }
		       });
       $curr_dom = $curr_dom.next();
     }
   };
   KtSt1St2TableHandler.prototype._show_or_hide_st2_row = function(subtype1)
   {
     // show or hide the rows accordingly
     var $row = $('tr[table_id=' + this.table_id + '][subtype1='+subtype1+'][class="st1_row"]');
     if ($row.length == 0)
       return;
     var $curr_dom = $row.next();
     if(this.row_click_state[subtype1] != undefined &&
	this.row_click_state[subtype1][0] == true)
     {
       $row.contents().find("img.plus").hide();
       $row.contents().find("img.minus").show();
       while($curr_dom.attr('class') == "st2_row" && $curr_dom.length != 0)
       {
	 $curr_dom.show();
	 var subtype2 = '';
	 if($curr_dom.attr('subtype2') != undefined)
	   subtype2 = $curr_dom.attr('subtype2');
	 this._show_or_hide_st3_row(subtype1, subtype2);
	 $curr_dom = $curr_dom.next();
       }
     }
     else
     {
       $row.contents().find("img.plus").show();
       $row.contents().find("img.minus").hide();
       while($curr_dom.attr('class') != "st1_row" &&
	     $curr_dom.length != 0)
       {
	 $curr_dom.hide();
	 $curr_dom = $curr_dom.next();
       }
     }
   };
   KtSt1St2TableHandler.prototype._show_or_hide_st3_row = function(subtype1, subtype2)
   {
     var $row = $('tr[table_id=' + this.table_id + '][subtype1='+subtype1+'][subtype2='+subtype2+'][class="st2_row"]');
     if($row.length == 0)
       return;

     var $curr_dom = $row.next();
     if(this.row_click_state[subtype1][1][subtype2] != undefined &&
	this.row_click_state[subtype1][1][subtype2] == true)
     {
       $row.contents().find("img.plus").hide();
       $row.contents().find("img.minus").show();
       while($curr_dom.attr('class') == 'st3_row')
       {
	 $curr_dom.show();
	 $curr_dom = $curr_dom.next();
       }
     }
     else
     {
       $row.contents().find("img.plus").show();
       $row.contents().find("img.minus").hide();

       while($curr_dom.attr('class') == 'st3_row')
       {
	 $curr_dom.hide();
	 $curr_dom = $curr_dom.next();
       }
     }
   };
   KtSt1St2TableHandler.prototype._show_or_hide_all = function()
   {
     for(var st1_key in this.st2_data)
     {
       this._show_or_hide_st2_row(st1_key);
     }
   };
   KtSt1St2TableHandler.prototype._populate_all_cached_st2_rows = function()
   {
     for(var st1_key in this.st2_data)
     {
       this._populate_cached_st2_row(st1_key);

     }
   };
   KtSt1St2TableHandler.prototype._populate_all_cached_st3_rows = function()
   {
     for(var st1_key in this.st3_data)
     {
       var st3_data = this.st3_data[st1_key];
       for(var st2_key in st3_data)
       {
	 this._populate_cached_st3_row(st1_key,st2_key);
       }
     }
   };


   KtSt1St2TableHandler.prototype._delete_st2_from_cache = function(st1, st2)
   {
     if(this.st2_data[st1] != undefined){
       var st2_data_lst = this.st2_data[st1];
       var len = st2_data_lst.length;
       if(st2 != undefined && st2 != null){
	 for(var i = 0; i < len; i++){
	   if(st2_data_lst[i]['subtype2'] == st2){
	     st2_data_lst[i]['deleted'] = true;
	     break;
	   }
	 }// for
       }else{
	 for(var i = 0; i < len; i++){
	   st2_data_lst[i]['deleted'] = true;
	 }
       }
     }
     this._delete_st3_from_cache(st1,st2);
   };

   KtSt1St2TableHandler.prototype._delete_st3_from_cache = function(st1, st2, st3)
   {
     if(this.st3_data[st1] != undefined && this.st3_data[st1][st2] != undefined){
       var st3_data_lst = this.st3_data[st1][st2];
       var len = st3_data_lst.length;
       if(st3 != undefined && st3 != null){
	 for(var i = 0; i < len; i++){
	   if(st3_data_lst[i]['subtype3'] == st3){
	     st3_data_lst[i]['deleted'] = true;
	   }// if(st3_data_lst[i]['subtype3'] == st3) ...
	   break;
	 }// for(var i ...
       }else{
	 //st3 is not specified, so delete all st3 associated with st1 and st2
	 for(var i = 0; i < len; i++){
	   st3_data_lst[i]['deleted'] = true;
	 }// for
       }// else
     }
   };

   KtSt1St2TableHandler.prototype._delete_row_handler_get_ajax_args = function(dom)
   {
     var this_row = $(dom).parent().parent();
     var channel_type = $(dom).attr('channel_type');
     var row_type = $(this_row).attr('class');

     var arg = {channel_type:channel_type};
     // clean up the row_click_state while at it
     // also, clean up the st2 and st3 cache while at it.
     if(row_type == 'st1_row'){
       var st1 = $(this_row).attr('subtype1');
       arg['st1'] = st1;
       if(this.row_click_state[st1] != undefined){
	 delete this.row_click_state[st1];
       }
       this._delete_st2_from_cache(st1);
     }else if(row_type == 'st2_row'){
       var st1 = $(this_row).attr('subtype1');
       var st2 = $(this_row).attr('subtype2');
       arg['st1'] = st1;
       arg['st2'] = st2;
       if(this.row_click_state[st1][1][st2] != undefined){
	 delete this.row_click_state[st1][1][st2];
       }
       this._delete_st2_from_cache(st1,st2);
     }else if(row_type == 'st3_row'){
       var st1 = $(this_row).attr('subtype1');
       var st2 = $(this_row).attr('subtype2');
       var st3 = $(this_row).attr('subtype3');
       arg['st1'] = st1;
       arg['st2'] = st2;
       arg['st3'] = st3;
       this._delete_st3_from_cache(st1,st2,st3);
     }
     return arg;
   };

   KtSt1St2TableHandler.prototype._bind_table_events = function()
   {
     var this_obj = this;
     $("#"+this_obj.table_id+"_table tr.st1_row").click(
       function(event){
	 var $og_target = $(event.target);
	 if($og_target.hasClass('remove_btn')){
	   // remove event
	   this_obj._delete_row_handler(event.target);
	 }
	 else
	 {
	   // normal toggle event
	   var $row = $(this);
	   if($row.attr('expandable') == 'true')
	   {
	     var subtype1 = ($($($(this).children()[1]).children()[0]).text());

	     // update the click state first
	     var need_to_fetch_data = false;
	     if( this_obj.row_click_state[subtype1] == undefined )
	     {
	       this_obj.row_click_state[subtype1] = [true,{}];
	       need_to_fetch_data = true;
	     }
	     else
	     {
	       this_obj.row_click_state[subtype1][0] = !this_obj.row_click_state[subtype1][0];
	     }

	     if(need_to_fetch_data)
	     {
               $row.find('img.plus').hide();
               $row.find('img.loading').show();
	       var url = this_obj.options['root_url'] + '/np_ajax/' + this_obj.options['tab'] + "/" + this_obj.options['page'] + "/" + this_obj.table_id + '/?t=j&fcsst1=' + encodeURIComponent(subtype1) + '&groupby=' + encodeURIComponent(subtype1);
	       $.ajax(
		 {
		   type : 'GET',
		   url  : url,
		   dataType : 'json',
		   success : function(data, textStatus){
		     // cache the subtype2 data
		     this_obj.st2_data[subtype1] = data;
		     this_obj._populate_cached_st2_row(subtype1);
		     this_obj._show_or_hide_st2_row(subtype1);
                     $row.find('img.loading').hide();
		     this_obj._get_rid_of_st2_arrows(data, subtype1);
		   }// success
		 }
	       );
	     }
	     else
	     {
	       this_obj._show_or_hide_st2_row(subtype1);
	     }
	   }
	 }
	 return false;
       }
     );
   };

   function KtSt1St2Table()
   {
     this.inheritedFrom = KtTable;
   };

   KtSt1St2Table.prototype = new KtTable();
   KtSt1St2Table.prototype._init = function()
   {
     this.handler = new KtSt1St2TableHandler(this.element, this.options);
     this.handler.init_impl();
   };

   //////////////////////// KtPaginatedTable ///////////////////////////
   function KtPaginatedTableHandler(element, options){
     this.inheritedFrom = KtTableHandler;
     this.inheritedFrom(element, options);
     this.pagination = null;
   }

   KtPaginatedTableHandler.prototype = new KtTableHandler();
   KtPaginatedTableHandler.prototype.init_impl = function()
   {
     // call parent's method
     KtTableHandler.prototype.init_impl.call(this);
   };

   KtPaginatedTableHandler.prototype._ajax_load_all_table_data_handler = function(data){
     $("#"+this.table_id+"_table").find(".loading-row").remove();
     $("#t" + this.table_id + " a[id='prev']").unbind('click');
     $("#t" + this.table_id + " a[id='next']").unbind('click');

     this.data = data;
     // TODO: make the number of paginated rows customizable.
     this.pagination = new Pagination(this.data, this.table_id, 10);

      $("#"+this.table_id+"_table").ktTemplate('render', {
  						 list: this._format_data(this.pagination.getData(0))
  					      });
     this._bind_table_events();
   };

   function KtPaginatedHeader(show_frame){
     if(show_frame == true)
        {
        var template_str =
            "<div class='k-box'> \
                <div class='k-box-head'> \
                    <div class='k-box-head-info'>\
                        <h1>[=title]</h1> \
                        <a href='#' index='[=index]' class='help' title='[=bubble_text]'>help</a> \
                        <a href='#' class='export' id='[=data_export_id]'>Export</a>\
                    </div> \
                </div>\
                <div class='k-box-body'> \
                    <ul>\
                        <li class ='first'><a id='prev' href='#'><span id='prev_text' style='display:none'>Prev</span></a></li>\
                        <li class ='first'><a id='prev_inactive'' style='background: none'><span id='prev_text_inactive' style='background: none; color:#999999; display:none'>Prev</span></a></li>\
                        <li><span class='table_pagination'>Page&nbsp;</span><span class='table_pagination' id='curr_page'></span><span class='table_pagination'>&nbsp;of&nbsp;</span><span id='max_page'' class='table_pagination'></span></li>\
                        <li><a id='next' href='#'><span id='next_text' style='display:none'>Next</span></a></li>\
                        <li><a id='next_inactive' style='background: none'><span id='next_text_inactive' style='background: none; color:#999999; display:none'>Next</span></a></li>\
                     </ul>\
                     <table class='k-table' id='[=table_id]_table' cellpadding=\"0\" cellspacing=\"0\" border=\"0\"  id=\"data\" style=\"width: 100%\"> \
                        <tr class=\"head-tr left-border\"> \
                            <td class='lit first-coln [=first_coln.coln_type] [=first_coln.coln_class]' decimal='[=first_coln.coln_decimal]' coln_id='[=first_coln.coln_id]' width='[=first_coln.coln_width]'><h5>[=first_coln.coln_name]</h5></td>\
                            [[for coln in coln_list]] \
                            <td class='lit [=coln.coln_type] [=coln.coln_class]' decimal='[=coln.coln_decimal]' coln_id='[=coln.coln_id]' width='[=coln.coln_width]'><h5>[=coln.coln_name]</h5></td>\
                            [[endfor]]\
                        </tr>\
                    </table>\
                </div>\
            </div>";
        }
        else
        {
        var template_str =
            "<div class='k-box'> \
                <div class='k-box-body'> \
                    <ul>\
                        <li class ='first'><a id='prev' href='#'><span id='prev_text' style='display:none'>Prev</span></a></li>\
                        <li class ='first'><a id='prev_inactive'' style='background: none'><span id='prev_text_inactive' style='background: none; color:#999999; display:none'>Prev</span></a></li>\
                          <li><span class='table_pagination'>Page&nbsp;</span><span class='table_pagination' id='curr_page'></span><span class='table_pagination'>&nbsp;of&nbsp;</span><span id='max_page'' class='table_pagination'></span></li>\
                        <li><a id='next' href='#'><span id='next_text' style='display:none'>Next</span></a></li>\
                        <li><a id='next_inactive' style='background: none'><span id='next_text_inactive' style='background: none; color:#999999; display:none'>Next</span></a></li>\
                     </ul>\
                     <table class='k-table' id='[=table_id]_table' cellpadding=\"0\" cellspacing=\"0\" border=\"0\"  id=\"data\" style=\"width: 100%\"> \
                        <tr class=\"head-tr left-border\"> \
                            <td decimal='[=first_coln.coln_decimal]' class='lit first-coln [=first_coln.coln_type] [=first_coln.coln_class]' coln_id='[=first_coln.coln_id]' width='[=first_coln.coln_width]'><h5>[=first_coln.coln_name]</h5></td>\
                            [[for coln in coln_list]] \
                            <td decimal='[=coln.coln_decimal]' class='lit [=coln.coln_type] [=coln.coln_class]' coln_id='[=coln.coln_id]' width='[=coln.coln_width]'><h5>[=coln.coln_name]</h5></td>\
                            [[endfor]]\
                        </tr>\
                    </table>\
                </div>\
            </div>";
        }
        return template_str;
   };

   KtPaginatedTableHandler.prototype._get_table_header = function(show_frame){
        return KtPaginatedHeader(show_frame);
   };

   KtPaginatedTableHandler.prototype._bind_table_events = function()
   {
     this.show_hide_prev_next_btn();
     this.bind_prev_click();
     this.bind_post_click();
     $("#t"+this.table_id + " span[id='curr_page']").text(this.pagination.page+1);
     $("#t"+this.table_id + " span[id='max_page']").text(this.pagination.max_page);
   };

   KtPaginatedTableHandler.prototype.show_hide_prev_next_btn = function()
   {
     if(this.pagination.page == 0)
     {
       //deactivate prev
       $("#t"+this.table_id + " span[id='prev_text_inactive']").show();
       $("#t"+this.table_id + " span[id='prev_text']").hide();
     }
     else
     {
       $("#t"+this.table_id + " span[id='prev_text_inactive']").hide();
       $("#t"+this.table_id + " span[id='prev_text']").show();
     }

     if(this.pagination.page == this.pagination.max_page - 1)
     {
       $("#t"+this.table_id + " span[id='next_text_inactive']").show();
       $("#t"+this.table_id + " span[id='next_text']").hide();
     }
     else
     {
       $("#t"+this.table_id + " span[id='next_text_inactive']").hide();
       $("#t"+this.table_id + " span[id='next_text']").show();
     }
   };

   KtPaginatedTableHandler.prototype.bind_prev_click = function()
   {
     var this_obj = this;
     var $header_td_obj = $($(this._gen_table_id() + " td")[0]);
     var og_height = $header_td_obj.height();
     $("#t" + this.table_id + " a[id='prev']").click(
       function(){
	 this_obj._clear_content();
	 var data = this_obj.pagination.getPrevData();
	 $(this_obj._gen_table_id()).ktTemplate('render', {
					      list: this_obj._format_data(data)
					    });
	 this_obj.show_hide_prev_next_btn();
	 $("#t"+this_obj.table_id + " span[id='curr_page']").text(this_obj.pagination.page+1);

	 return false;
       }
     );
     $header_td_obj.height(og_height); //hack to work around the column shrinkage problem
   };

   KtPaginatedTableHandler.prototype.bind_post_click = function()
   {
     var this_obj = this;
     var $header_td_obj = $($(this._gen_table_id() + " td")[0]);
     var og_height = $header_td_obj.height();
     $("#t" + this_obj.table_id + " a[id='next']").click(
       function(){
	 this_obj._clear_content();
	 var data = this_obj.pagination.getNextData();
	 $(this_obj._gen_table_id()).ktTemplate('render', {
					      list: this_obj._format_data(data)
					    });
	 this_obj.show_hide_prev_next_btn();
	 $("#t"+this_obj.table_id + " span[id='curr_page']").text(this_obj.pagination.page+1);
	 return false;
       }
     );
     $header_td_obj.height(og_height); //hack to work around the column shrinkage problem
   };

   KtPaginatedTableHandler.prototype._sort = function(coln_id, data){
     //do some bookkeeping first
     this.sort_dict[coln_id] = !this.sort_dict[coln_id];

     this._sort_impl(coln_id, data);
     var curr_page = this.pagination.page;
     this.pagination = new Pagination(this.data, this.table_id, 10); //TODO: customize how many is showing per paginated page.
     this.pagination.page = curr_page;
     // repopulate data
     this._clear_content();
     $(this._gen_table_id()).ktTemplate('render', {
					  list: this._format_data(this.pagination.getData(curr_page))
					});
   };

   function KtPaginatedTable()
   {
     this.inheritedFrom = KtTable;
   }

   KtPaginatedTable.prototype = new KtTable();
   KtPaginatedTable.prototype._init = function()
   {
     this.handler = new KtPaginatedTableHandler(this.element, this.options);
     this.handler.init_impl();
   };

    ////////////////// KtPaginatedTableNotPermitted //////////////////////

    function KtPaginatedTableNotPermittedHandler(element, options){
     this.inheritedFrom = KtNotPermittedTableHandler;
     this.inheritedFrom(element, options);
     this.pagination = null;
   }

   KtPaginatedTableNotPermittedHandler.prototype = new KtNotPermittedTableHandler();


    KtPaginatedTableNotPermittedHandler.prototype._get_table_header = function(show_frame){
        return KtPaginatedHeader(show_frame);
    };

    function KtPaginatedTableNotPermitted()
   {
     this.inheritedFrom = KtNotPermittedTable;
   }

   KtPaginatedTableNotPermitted.prototype = new KtNotPermittedTable();
   KtPaginatedTableNotPermitted.prototype._init = function()
   {
     this.handler = new KtPaginatedTableNotPermittedHandler(this.element, this.options);
     this.handler.init_impl();
   };

   //////////////////////// KtSubTabTable ///////////////////////////
   function KtSubTabTableHandler(element, options){
     this.inheritedFrom = KtTableHandler;
     this.inheritedFrom(element, options);
     this.pagination = null;
   }

   KtSubTabTableHandler.prototype = new KtTableHandler();

   KtSubTabTableHandler.prototype._highlight_selected_tab = function(tab_str)
   {
     if(tab_str == undefined)
     {
       //pick the first one
       $($("#t" + this.table_id + " div.k-box-body a")[0]).addClass('active');
     }
     else
     {
       $("#t" + this.table_id + " a[subTab='"+ tab_str +"']").addClass('active');
     }
   };

   KtSubTabTableHandler.prototype._bind_sub_tab_events = function()
   {
     var _this_obj = this;
     $("#t" + this.table_id + " div.k-box-body a").click(
       function()
       {
	 var tab_str = $($(this).children()[0]).text();
	 var url = _this_obj.root_url + '/np_ajax/' + _this_obj.tab + '/' + _this_obj.page + '/' + _this_obj.table_id + '/?t=j&table_sub_tab=' + escape(tab_str);
	 var element = this;
 	 $.ajax(
 	   {
 	     type     : 'GET',
 	     url      : url,
 	     dataType : 'json',
 	     success  : function(data, textStatus){
 	       _this_obj.options['coln'] = data['__colns__'];
 	       $(_this_obj.element).ktTemplate('clear');
 	       _this_obj._construct_coln_header(true);
 	       _this_obj._bind_sub_tab_events(); // this is not a recursive call.
 	       _this_obj._setup_rows_template(data['__rows__']); //setup the table content template
	       _this_obj._highlight_selected_tab(tab_str);
	       _this_obj._setup_sorting();
 	       $(document).trigger('load_all_table_data', [_this_obj.table_id] );
 	     }
 	   }
 	 );
	 return false;
       }
     );
   };

   KtSubTabTableHandler.prototype.init_impl = function()
   {
     // call parent's method
     KtTableHandler.prototype.init_impl.call(this);
     this._bind_sub_tab_events();
     this._highlight_selected_tab();
   };


   KtSubTabTableHandler.prototype._get_table_header = function(show_frame){
     if(show_frame == true){
       var template_str =
       "<div class='k-box'> \
	       <div class='k-box-head'> \
	          <div class='k-box-head-info'>\
		      <h1>[=title]</h1> \
                      <a href='#' index='[=index]' class='help' title='[=bubble_text]'>help</a> \
		      <a href='#' class='export' id='[=data_export_id]'>Export</a>\
		  </div> \
	       </div>\
	       <div class='k-box-body'> \
                 <ul>\
		   [[for tab in subtab]]\
       	           <li><a href='#' subTab='[=tab]'><span>[=tab]</span></a></li>\
	           [[endfor]]\
	 	 </ul>\
 		 <table class='k-table' id='[=table_id]_table' \
			cellpadding=\"0\" cellspacing=\"0\" border=\"0\"  id=\"data\" style=\"width: 100%\"> \
		   <tr class=\"head-tr left-border\"> \
		     <td decimal='[=first_coln.coln_decimal]' class='lit first-coln [=first_coln.coln_type] [=first_coln.coln_class]' coln_id='[=first_coln.coln_id]' width='[=first_coln.coln_width]'><h5>[=first_coln.coln_name]</h5></td>\
                     [[for coln in coln_list]] \
                     <td decimal='[=coln.coln_decimal]' class='lit [=coln.coln_type] [=coln.coln_class]' coln_id='[=coln.coln_id]' width='[=coln.coln_width]'><h5>[=coln.coln_name]</h5></td>\
	             [[endfor]]\
		   </tr>\
		 </table>\
	       </div>\
	   </div>";
     }
     else
     {

     }
     return template_str;
   };

   function KtSubTabTable()
   {
     this.inheritedFrom = KtTable;
   };

   KtSubTabTable.prototype = new KtTable();
   KtSubTabTable.prototype._init = function()
   {
     this.handler = new KtSubTabTableHandler(this.element, this.options);
     this.handler.init_impl();
   };

   //////////////////////// KtSubTabTableRefactored ///////////////////////////
   function KtSubTabTableRefactoredHandler(element, options)
   {
     this.inheritedFrom = KtTableHandler;
     this.inheritedFrom(element, options);
   }
   KtSubTabTableRefactoredHandler.prototype = new KtTableHandler();

   KtSubTabTableRefactoredHandler.prototype._get_table_header = function(show_frame)
   {
     var template_str =
       "<div id='[=table_id]_secondary_data' class='k-box-secondary'></div>\
        <div class='k-box'> \
	       <div class='k-box-head'> \
	          <div class='k-box-head-info'>\
		      <h1>[=title]</h1> \
                      <a href='#' index='[=index]' class='help' title='[=bubble_text]'>help</a> \
		      <a href='#' class='export' id='[=data_export_id]'>Export</a>\
		  </div> \
	       </div>\
	       <div class='k-box-body'> \
                 <ul>\
		   [[for tab in subtab]]\
       	           <li><a href='#' subTab='[=tab.tab_id]'><span>[=tab.tab_str]</span></a></li>\
	           [[endfor]]\
	 	 </ul>\
               </div>\
       </div>";
     return template_str;
   };

   KtSubTabTableRefactoredHandler.prototype._load_all_table_data_handler = function()
   {
     //do nothing.
   };

   KtSubTabTableRefactoredHandler.prototype._export_handler = function(){
     var subtab_id = $("#t" + this.table_id + " a[class='active']").attr('subtab');
     var data_export_url = this.root_url + '/np_data_export/' + this.tab + '/' + this.page + '/' + subtab_id + '/?t=j';
     document.location = data_export_url;
     return false;
   };

   KtSubTabTableRefactoredHandler.prototype._push_secondary_data_to_parent = function(tab_id_str)
   {
     var $secondary_data_dom = $("#" + tab_id_str + "_secondary_data");
     if($secondary_data_dom.length > 0)
     {
       $("#" + this.table_id + "_secondary_data").text($secondary_data_dom.text());
     }
   };

   KtSubTabTableRefactoredHandler.prototype._highlight_selected_tab = function(tab_id_str)
   {
     if(tab_id_str == undefined)
     {
       //pick the first one
       $($("#t" + this.table_id + " div.k-box-body a")[0]).addClass('active');
       tab_id_str = $($("#t" + this.table_id + " div.k-box-body a")[0]).attr('subtab');
     }
     else
     {
       $("#t" + this.table_id + " a[subTab='"+ tab_id_str +"']").addClass('active');
     }

     var _this_obj = this;
     $(document).bind('onload_all_table_data', function(event, msg)
		      {
			if(tab_id_str == msg)
			{
			  _this_obj._push_secondary_data_to_parent(tab_id_str);
			}
		      });
   };

   KtSubTabTableRefactoredHandler.prototype._unhighlight_selected_tab = function(tab_id_str)
   {
     $("#t" + this.table_id + " a[subTab='"+ tab_id_str +"']").removeClass('active');
   };

   KtSubTabTableRefactoredHandler.prototype._bind_sub_tab_events = function(){
     var _this_obj = this;
     $("#t" + this.table_id + " div.k-box-body a").click(
       function()
       {
	 var tab_table_index_list = _this_obj.options['table_widget_ids'];
	 var tab_table_index_list_len = tab_table_index_list.length;
	 for(var i = 0; i < tab_table_index_list_len; i++)
	 {
	   var sub_tab_index = tab_table_index_list[i]['index'];
	   if(sub_tab_index == $(this).attr('subtab'))
	   {
	     $("#t"+sub_tab_index).show();
	     _this_obj._highlight_selected_tab(sub_tab_index);
	     _this_obj._push_secondary_data_to_parent(sub_tab_index+"_tab");
	   }
	   else
	   {
	     $("#t"+sub_tab_index).hide();
	     _this_obj._unhighlight_selected_tab(sub_tab_index);
	   }
	 }
	 return false;
       }
     );
   };

   KtSubTabTableRefactoredHandler.prototype.init_impl = function()
   {
     KtTableHandler.prototype.init_impl.call(this);

     var tab_table_index_list = this.options['table_widget_ids'];
     var tab_table_index_list_len = tab_table_index_list.length;
     for(var i = 0; i < tab_table_index_list_len; i++)
     {
       $("#t" + this.table_id + " div[class='k-box-body']").append($("#t"+tab_table_index_list[i]['index']));
     }
     this._bind_sub_tab_events();
     this._highlight_selected_tab();
     // unbind load_all_table_data
   };

   function KtSubTabTableRefactored()
   {
     //     this.handler = new KtSubTabTableHandler(this.element, this.options);
     this.inheritedFrom = KtTable;
   }


   KtSubTabTableRefactored.prototype._init = function()
   {
     this.handler = new KtSubTabTableRefactoredHandler(this.element, this.options);
     this.handler.init_impl();
   };


   //////////////////////// KtFiltersForDynTable ///////////////////////////
   function KtFilterForDynTableHandler(element, options){
     this.inheritedFrom = KtTableHandler;
     this.inheritedFrom(element, options);
   };

   KtFilterForDynTableHandler.prototype = new KtTableHandler();

   KtFilterForDynTableHandler.prototype._delete_row_handler = function(dom)
   {
     var filter_id = $(dom).parent().next().children().children().attr('filter_id');
     var _this_obj = this;
     $.ajax(
       {
	 type: "GET",
	 url : "/dashboard/filter/ajax_delete_filter/",
	 data: {id: filter_id},
	 success: function(msg){
	   _this_obj._trigger_load_table_data();
	 }
       });
     return false;
   };

   KtFilterForDynTableHandler.prototype._toggle_filter = function(dom)
   {
     var _this_obj = this;
     var filter_id = $(dom).parent().attr('filter_id');
     var myImage = dom;
     var yes = kt_media_url + '/images/green-ball.png';
     var wait = kt_media_url + '/images/yellow-ball.png';
     var no = kt_media_url + '/images/red-ball.png';

     //$(dom).parent().parent().parent().next(); //st1

     $(myImage).attr("src",wait);

     $.ajax(
       {
	 type: "GET",
	 url : "/dashboard/filter/ajax_toggle_filter/",
	 data: { id: filter_id },
	 success: function(msg){
	   if (msg == '1'){
             $(myImage).attr("src",yes);
           }
           else if(msg == '0'){
             $(myImage).attr("src",no);
           }
	   _this_obj._trigger_load_table_data();
	 }
       });
     return false;
   };

   KtFilterForDynTableHandler.prototype._bind_table_events = function()
   {
     var $remove_btns = $("#"+ this.table_id +"_table a.remove_btn");
     var this_obj = this;
     if($remove_btns.length > 0){
       $remove_btns.click(function(event){
			    this_obj._delete_row_handler(event.target);
			  });
     }

     var $toggle_btns = $("#"+this.table_id +"_table a.filter_toggle_btn");
     if($toggle_btns.length > 0){
       $toggle_btns.click(function(event){
			    this_obj._toggle_filter(event.target);
			  });
     }
   };

   function KtFilterForDynTable()
   {
     this.inheritedFrom = KtTable;
   };
   KtFilterForDynTable.prototype = new KtTable();
   KtFilterForDynTable.prototype._init = function()
   {
     this.handler = new KtFilterForDynTableHandler(this.element, this.options);
     this.handler.init_impl();
   };


   ////////////////////////  ktFilterForSt1St2Table ///////////////////////////
   function KtFilterForSt1St2TableHandler(element, options){
     this.inheritedFrom = KtFilterForDynTableHandler;
     this.inheritedFrom(element, options);
   }

   KtFilterForSt1St2TableHandler.prototype = new KtFilterForDynTableHandler();

   KtFilterForSt1St2TableHandler.prototype._delete_row_handler = function(dom)
   {
     var filter_id = $(dom).parent().next().children().children().attr('filter_id');
     var _this_obj = this;
     $.ajax(
       {
	 type: "GET",
	 url : "/dashboard/filter/ajax_delete_filter/",
	 data: {id: filter_id},
	 success: function(msg){
	   var $st1_dom = $(dom).parent().next().next();
	   var $st2_dom = $st1_dom.next();
	   var $st3_dom = $st2_dom.next();
	   var st1_text = $st1_dom.text();
	   var st2_text = $st2_dom.text();
	   var st3_text = $st3_dom.text();

	   var table_id = '#t' + _this_obj.table_id.split("_")[0];
	   var table_widget_ids = $(table_id).ktSubTabTableRefactored("option", "table_widget_ids");
	   for(var i = 0; i< table_widget_ids.length; i++){
	     $(document).trigger('delete_st2st3', [table_widget_ids[i]['index'],
						   st1_text,
						   st2_text,
						   st3_text]);
	   }
	   _this_obj._trigger_load_table_data();
	 }// success
       });
     return false;
   };

   KtFilterForSt1St2TableHandler.prototype._toggle_filter = function(dom){
     KtFilterForDynTableHandler.prototype._toggle_filter.call(this, dom);
     var $st1_dom = $(dom).parent().parent().parent().next();
     var $st2_dom = $st1_dom.next();
     var $st3_dom = $st2_dom.next();
     var st1_text = $st1_dom.text();
     var st2_text = $st2_dom.text();
     var st3_text = $st3_dom.text();

     var table_id = '#t'+this.table_id.split("_")[0];
     var table_widget_ids = $(table_id).ktSubTabTableRefactored("option", "table_widget_ids");
     for(var i = 0; i< table_widget_ids.length; i++){
       $(document).trigger('toggle_st2st3', [table_widget_ids[i]['index'],
					       st1_text,
					       st2_text,
					       st3_text]);
     }
     return false;
   };

   function KtFilterForSt1St2Table()
   {
     this.inheritedFrom = KtFilterForDynTable;
   }
   KtFilterForSt1St2Table.prototype = new KtFilterForDynTable();
   KtFilterForSt1St2Table.prototype._init = function()
   {
     this.handler = new KtFilterForSt1St2TableHandler(this.element, this.options);
     this.handler.init_impl();
   };

   var kt_table = new KtTable();
   var kt_not_permitted_table = new KtNotPermittedTable();
   var kt_st1_st2_table = new KtSt1St2Table();
   var kt_paginated_table = new KtPaginatedTable();
   var kt_paginated_table_not_permitted = new KtPaginatedTableNotPermitted();
   var kt_sub_tab_table = new KtSubTabTable();
   var kt_sub_tab_table_refactored = new KtSubTabTableRefactored();
   var kt_filter_for_dyn_table = new KtFilterForDynTable();
   var kt_filter_for_st1_st2_table = new KtFilterForSt1St2Table();

   $.widget("kt.ktTable", kt_table);
   $.widget("kt.ktNotPermittedTable", kt_not_permitted_table);
   $.widget("kt.ktSt1St2Table", kt_st1_st2_table);
   $.widget("kt.ktPaginatedTable", kt_paginated_table);
   $.widget("kt.ktPaginatedTableNotPermitted", kt_paginated_table_not_permitted);
   $.widget("kt.ktSubTabTable", kt_sub_tab_table);
   $.widget("kt.ktSubTabTableRefactored", kt_sub_tab_table_refactored);
   $.widget("kt.ktFilterForDynTable", kt_filter_for_dyn_table);
   $.widget("kt.ktFilterForSt1St2Table", kt_filter_for_st1_st2_table);

   $.kt.ktTable.getter = ["get_handler"];
   $.kt.ktSt1St2Table.getter = ["get_handler"];
   $.kt.ktPaginatedTable.getter = ["get_handler"];
   $.kt.ktSubTabTable.getter = ["get_handler"];
   $.kt.ktSubTabTableRefactored.getter = ["get_handler"];
 })(jQuery);
