/*
 * Copyright 2006 Mask@ Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
/**
 * JavaScriptオブジェクトとRialtoオブジェクトをWrapして統一のインターフェースを提供する。
 */

function ObjWrapper(object){
  this.obj = object;
}

ObjWrapper.prototype.isMultiSelect = function(){
  if (maskat.isRialtoObj(this.obj)){
    switch (this.obj.type){ // [RialtoAPI依存]
      case "grid":
        return this.obj.multiSelect; // [RialtoAPI依存]
      case "treeview":
        return false; // treeviewは現状、複数選択不可能
      default:
        break;
    }
  }
  throw new MaskatError({name: "Type Error",
                         message: "このオブジェクトに対してこの関数は実行できません。",
                         fileName: "objWrapper.js",
                         functionName: "ObjWrapper.prototype.isMultiSelect"});
}

ObjWrapper.prototype.isSingleDataObj = function(){
  if (maskat.isRialtoObj(this.obj)){
    // this.objはRialtoオブジェクト
    switch (this.obj.type){  // [RialtoAPI依存]
      case "label":
      case "text":
      case "combo":
      case "checkbox":
      case "radioGroup":
      case "codelib":
      case "divHtml":
        return true;
      default:
        return false;
    }
  }
  else {
    // this.objはJavaScriptオブジェクト
    return !maskat.isArray(this.obj);
  }
}

ObjWrapper.prototype.isMultiDataObj = function(){
  if (maskat.isRialtoObj(this.obj)){
    // this.objはRialtoオブジェクト
    switch (this.obj.type){ // [RialtoAPI依存]
      case "grid":
      case "treeview":
        return true;
      default:
        return false;
    }
  }
  else {
    // this.objはJavaScriptオブジェクト
    return maskat.isArray(this.obj);  // TODO: 2次元配列指定にする？
  }
}


ObjWrapper.prototype.getSingleValue = function(){
  if (!this.isSingleDataObj()){
    throw new MaskatError({name: "Type Error",
                           message: "複数データ型のオブジェクトに対してこの関数は実行できません。",
                           fileName: "objWrapper.js",
                           functionName: "ObjWrapper.prototype.getSingleValue"});
  }
  else {
    if (maskat.isRialtoObj(this.obj)){
      switch (this.obj.type){
        case "label":
          return this.obj.text;  // [RialtoAPI依存] getterAPIがないので直接textプロパティを参照
        case "text":
          return this.obj.getValue();  // [RialtoAPI依存] rialto.widget.Text.prototype.getValue
        case "combo":
          return this.obj.getSelValue();  // [RialtoAPI依存] rialto.widget.Combo.prototype.getSelValue
        case "checkbox":
          // boolean値ではなく文字列として返す
          return "" + this.obj.getCheck();  // [RialtoAPI依存] rialto.widget.Checkbox.prototype.getCheck, rialto.widget.Radio.prototype.getCheck
        case "radioGroup":
          return this.obj.getSelValue();
        case "codelib":
          return this.obj.getValue();
        default:
          break;
      }
    }
    else{
      // JavaScriptオブジェクト
      return this.obj;
    }
  }
}

ObjWrapper.prototype.setSingleValue = function(val){
  if (!this.isSingleDataObj()){
    throw new MaskatError({name: "Type Error",
                           message: "複数データ型のオブジェクトに対してこの関数は実行できません。",
                           fileName: "objWrapper.js",
                           functionName: "ObjWrapper.prototype.setSingleValue"});
  }
  else {
    if (maskat.isRialtoObj(this.obj)){
      switch (this.obj.type){  // [RialtoAPI依存]
        case "label":
          this.obj.setText(val);  // [RialtoAPI依存] rialto.widget.Label.prototype.setText
          break;
        case "text":
          this.obj.setValue(val);  // [RialtoAPI依存] rialto.widget.Text.prototype.setValue
          break;
        case "combo":
          this.obj.selWithValue(val);  // [RialtoAPI依存] rialto.widget.Combo.prototype.selWithValue
          break;
        case "checkbox":
          if (val == "true"){
            this.obj.setCheck(true);  // [RialtoAPI依存] rialto.widget.Checkbox.prototype.setCheck, rialto.widget.Radio.prototype.setCheck
          }
          else {
            this.obj.setCheck(false);  // [RialtoAPI依存] rialto.widget.Checkbox.prototype.setCheck, rialto.widget.Radio.prototype.setCheck
          }
          break;
        case "radioGroup":
          this.obj.setSelValue(val);
          break;
        case "divHtml":
          this.obj.setElement(val);
          break;
      }
    }
    else{
      // TODO: JavaScriptオブジェクトへのsetValue
      throw new Error("非rialtoオブジェクトはsetValueできない。"+this.obj.base);
    }
  }
}

ObjWrapper.prototype.setMultiValue = function(val){
  if (!this.isMultiDataObj()){
    throw new MaskatError({name: "Type Error",
                           message: "単一データ型のオブジェクトに対してこの関数は実行できません。",
                           fileName: "objWrapper.js",
                           functionName: "ObjWrapper.prototype.setValue"});
  }
  else {
    if (maskat.isRialtoObj(this.obj)){
      switch (this.obj.type){  // [RialtoAPI依存]
        case "grid":
          this.setGridValue(val);
          break;
        case "treeview":
          this.setTreeValue(val);
          break;
      }
    }
    else{
      // TODO: JavaScriptオブジェクトへのsetValue
    }
  }
}


ObjWrapper.prototype.setTreeValue = function(val){
  try {
    // 現在のツリーの全てのノードを削除
    if (this.obj.rootNode != null){  // [RialtoAPI依存]
        this.obj.rootNode.remove();  // このAPIでいいのか要チェック
        this.obj.rootNode = null;
    }

    for (var i = 0; i < val.length; i++){
      var parentName;
      if (!val[i]["PARENT"]){
        // ルートノードの場合
        parentName = this.obj.name;
      }
      else {
        parentName = val[i]["PARENT"];
      }
      eval(val[i]["NAME"] + "= " + this.obj.name + ".createAndAddNode(" + parentName + ".id,{name:'" + val[i]["NAME"] + "',text:'" + maskat.escapeDoubleQuote(val[i]["TEXT"]) + "',icon:'images/imTreeview/pict_synthetik_off.gif',icon2:'',open:true,reload:false,onclick:''});" );  // [RialtoAPI依存]
      
      for (var key in val[i]){
        if (key.charAt(0) == "_"){
          if(!(eval(val[i]["NAME"] + ".maskatHiddenField"))){
            eval(val[i]["NAME"] + ".maskatHiddenField = new Object();");
          }
          eval(val[i]["NAME"] + ".maskatHiddenField['" + key + "'] = '" + val[i][key] + "';");
        }
      }
      
    }
  }
  catch (e){
    throw e;
  }
}

ObjWrapper.prototype.setGridValue = function(val){
  try {
    if (val.length==0){
        this.obj.deleteLines();
        return;
    }
    var gridJSStr = "[";
    for (var i = 0; i < val.length; i++){
      gridJSStr += "[";
      for (var j in val[i]){
        var colIndex = parseInt(j);
        if (!isNaN(colIndex)) {// && colIndex < this.obj.NbreCol){  // [RialtoAPI依存] Gridオブジェクトの列数
          gridJSStr += '"' + maskat.escapeDoubleQuote(val[i][j]) + '",';  // TODO: itemValueから"を\"に変換
        }
      }
      gridJSStr = gridJSStr.substring(0, gridJSStr.length - 1);  // 最後の','を取り除く
      gridJSStr += "],";
    }
    gridJSStr = gridJSStr.substring(0, gridJSStr.length - 1);  // 最後の','を取り除く
    gridJSStr += "]";

    eval("this.obj.fillGrid(" + gridJSStr + ", 0, false)");
  }
  catch (e){
    throw e;
  }
}

ObjWrapper.prototype.getSelectedIndex = function(){
  if (maskat.isRialtoObj(this.obj)){
    switch (this.obj.type){ // [RialtoAPI依存]
      case "grid":
        return this.obj.indLineClic; // [RialtoAPI依存]
      case "treeview":
        if (this.obj.currentSelNode){
          return maskat.getTreeRowNumByName(this.obj, this.obj.currentSelNode.name);
        }
        else {
          return -1;
        }
      default:
        break;
    }
  }
  throw new MaskatError({name: "Type Error",
                         message: "このオブジェクトに対してこの関数は実行できません。",  // TODO: 詳細に
                         fileName: "objWrapper.js",
                         functionName: "ObjWrapper.prototype.getSelectedIndex"});
}


maskat.getTreeRowNumByName = function(treeview, name){
  if (!treeview.rootNode){
    return -1;
  }
  
  var treeNodeStack = new Array();
  treeNodeStack.push(treeview.rootNode);
  
  var rowNum = -1;
  
  while (treeNodeStack.length != 0){
    var treeNode = treeNodeStack.pop();
    rowNum++;
    if (treeNode.name == name){
      return rowNum;
    }
    else {
      if (treeNode.hasChild()){  // [RialtoAPI依存]
        for (var i = treeNode.arrChildNode.length - 1; i >= 0 ; i--){
          treeNodeStack.push(treeNode.arrChildNode[i]);
        }
      }
    }
  }
  
  // 最終的に見つからなかった場合(ありえない)
  return -1;
}


ObjWrapper.prototype.getSelectedIndexes = function(){
  if (maskat.isRialtoObj(this.obj)){
    switch (this.obj.type){ // [RialtoAPI依存]
      case "grid":
        var indexArray = new Array();
        for (var i = 0; i < this.obj.tabData.length; i++){ // [RialtoAPI依存]
          var lineData = this.obj.tabData[i]; // [RialtoAPI依存]
          if (lineData.sel == true){ // [RialtoAPI依存]
            indexArray.push(i);
          }
        }
        return indexArray;
      case "treeview":
        // TODO: 
      default:
        break;
    }
  }

  throw new MaskatError({name: "Type Error",
                         message: "このオブジェクトに対してこの関数は実行できません。",  // TODO: 詳細に
                         fileName: "objWrapper.js",
                         functionName: "ObjWrapper.prototype.getSelectedIndexes"});
}

ObjWrapper.prototype.getColNum = function(){
  if (maskat.isRialtoObj(this.obj)){
    switch (this.obj.type){ // [RialtoAPI依存]
      case "grid":
        return this.obj.NbreCol;  // [RialtoAPI依存]
      case "treeview":
        // TODO: 対象APIを探す。
      default:
        break;
    }
  }
  
  throw new MaskatError({name: "Type Error",
                         message: "このオブジェクトに対してこの関数は実行できません。",  // TODO: 詳細に
                         fileName: "objWrapper.js",
                         functionName: "ObjWrapper.prototype.getColLength"});
}

ObjWrapper.prototype.getRowNum = function(){
  if (maskat.isRialtoObj(this.obj)){
    switch (this.obj.type){ // [RialtoAPI依存]
      case "grid":
        if (this.obj.tabData){ // [RialtoAPI依存]
          return this.obj.tabData.length;  // [RialtoAPI依存]
        }
        else {
          return 0;
        }
      case "treeview":
        return maskat.countDescendantTreeNode(this.obj);
      default:
        break;
    }
  }
  else if (maskat.isArray(this.obj)){
    return this.obj.length;
  }
  
  throw new MaskatError({name: "Type Error",
                         message: "このオブジェクトに対してこの関数は実行できません。",  // TODO: 詳細に
                         fileName: "objWrapper.js",
                         functionName: "ObjWrapper.prototype.getRowNum"});
}


maskat.countDescendantTreeNode = function(treeview){
  if (!treeview.rootNode){  // [RialtoAPI依存]
    return 0;
  }

  var num = 0;
  var treeNodeArray = new Array();
  treeNodeArray.push(treeview.rootNode);  // [RialtoAPI依存]

  while (treeNodeArray.length != 0){
    treeNode = treeNodeArray.shift();
    num++;
    if (treeNode.hasChild()){
      for (var i = 0; i < treeNode.arrChildNode.length; i++){  // [RialtoAPI依存]
        treeNodeArray.push(treeNode.arrChildNode[i]);
      }
    }
  }
  return num;
}

ObjWrapper.prototype.getValueFromMultiData = function(row, col){
  if (maskat.isRialtoObj(this.obj)){
    switch (this.obj.type){ // [RialtoAPI依存]
      case "grid":
        return this.obj.tabData[row][col];  // [RialtoAPI依存]
      case "treeview":
        // row:行数, col:fromkey(ID/TEXT/PARENT)
        var treeNode = maskat.findTreeNodeByRowNum(this.obj, row);  // 同じ引数でfromkey分呼ばれるのでキャッシュすべき
        if (!treeNode){
          return null;
        }
        
        if (col.charAt(0) == "_"){
          if (!treeNode.maskatHiddenField){
            return "";
          }
          return treeNode.maskatHiddenField[col];
        }
        else{
          switch (col){
            case "NAME":
              return treeNode.name;
            case "TEXT":
              return treeNode.text;
            case "PARENT":
              if (treeNode.fatherNode){
                return treeNode.fatherNode.name;
              }
              else {
                return null;
              }
            default:
              throw new MaskatError({name: "EventXML Syntax Error",
                                     message: "Treeviewオブジェクトに対するfromkey'" + col + "'は未対応です。",
                                     fileName: "objWrapper.js",
                                     functionName: "ObjWrapper.prototype.getValueFromMultiData"});
          }
        }
      default:
        break;
    }
  }
  else if (maskat.isArray(this.obj)){  // TODO: 2次元配列チェックする？
    return this.obj[row][col];
  }
  else {
    throw new MaskatError({name: "Type Error",
                           message: "このオブジェクトに対してこの関数は実行できません。",  // TODO: 詳細に
                           fileName: "objWrapper.js",
                           functionName: "ObjWrapper.prototype.getValueFromMultiData"});
  }
}

maskat.findTreeNodeByRowNum = function(treeview, row){
  if (!treeview.rootNode || row == -1){
    return null;
  }
  
  var treeNodeStack = new Array();
  treeNodeStack.push(treeview.rootNode);

  var currentRow = -1;

  while (treeNodeStack.length != 0){
    var treeNode = treeNodeStack.pop();
    currentRow++;
    if (currentRow == row){
      return treeNode;
    }
    else {
      if (treeNode.hasChild()){  // [RialtoAPI依存]
        for (var i = treeNode.arrChildNode.length - 1; i >= 0 ; i--){
          treeNodeStack.push(treeNode.arrChildNode[i]);
        }
      }
    }
  }

  return null;

}




ObjWrapper.prototype.isJSObj = function(){
  return !maskat.isRialtoObj(this.obj);  // 将来Rialto以外のライブラリを利用する際は変更する
}

ObjWrapper.prototype.clear = function(){
  if (maskat.isRialtoObj(this.obj)){
    switch (this.obj.type){
      case "label":
        this.obj.setText("");  // [RialtoAPI依存] rialto.widget.Label.prototype.setText
        break;
      case "text":
        this.obj.setValue("");  // [RialtoAPI依存] rialto.widget.Text.prototype.setValue
        break;
      case "checkbox":
        this.obj.setCheck(false);  // [RialtoAPI依存] rialto.widget.Checkbox.prototype.setCheck, rialto.widget.Radio.prototype.setCheck
        break;
      case "radioGroup":
        this.obj.initRadio();
        break;
      case "grid":
        this.obj.initTab();
        break;
      case "treeview":
        if (this.obj.rootNode){  // [RialtoAPI依存]
          this.obj.rootNode.remove();  // このAPIでいいのか要チェック
          this.obj.rootNode = null;
        }
        break;
    }
  }
}

maskat.isRialtoObj = function(obj){
  return (obj && (typeof obj == "object") && (obj instanceof rialto.widget.AbstractComponent));
}

maskat.isArray = function(obj) {
  return (obj && (typeof obj == "object") && (obj.constructor == Array));
}

maskat.escapeDoubleQuote = function(str){
  return(str.split('"').join('\\"'));
}

//受信電文コンシューマー
//受信電文ノードからデータを取得して、オブジェクトに入れる
ObjWrapper.pluggableTeleConsumers={};

ObjWrapper.registerTeleConsumer = function(name,teleConsumer){
    ObjWrapper.pluggableTeleConsumers[name]=teleConsumer;
}

ObjWrapper.unregisterTeleConsumer = function(name){
    ObjWrapper.pluggableTeleConsumers[name]=null;
}

ObjWrapper.findTeleConsumer = function(teleType){
    return ObjWrapper.pluggableTeleConsumers[teleType];
}

//送信電文maker
//オブジェクトからデータを取得して、受信電文を組み立てる
ObjWrapper.pluggableTeleMakers={};

ObjWrapper.registerTeleMaker = function(name,maker){
    ObjWrapper.pluggableTeleMakers[name]=maker;
}

ObjWrapper.unregisterTeleMaker = function(name){
    ObjWrapper.pluggableTeleMakers[name]=null;
}

ObjWrapper.findTeleMaker = function(teleType){
    return ObjWrapper.pluggableTeleMakers[teleType];
}


//ワーカー、ローカルデータバインディング処理
ObjWrapper.pluggableLocalWorkers={};

ObjWrapper.registerLocalWorker = function(name,localWorker){
    ObjWrapper.pluggableLocalWorkers[name]=localWorker;
}

ObjWrapper.unregisterLocalWorker = function(name){
    ObjWrapper.pluggableLocalWorkers[name]=null;
}

ObjWrapper.findLocalWorker = function(workType){
    return ObjWrapper.pluggableLocalWorkers[workType];
}