//  Title: Chart - test-app.
//  Description: to test the Charts
//  Copyright: Copyright (c) 2010
//  Company: SiG Software Integration GmbH
//  Author Dr. Horst Walther

//  ----------------------------------------------------------------------------
function ChartTest (id, width, height, fill, opacity) {
  this.id = "ChartTest";
  var wordy = false;
  var chart = null;
  var StandardFactor = 1.5;
  var xdelta = 45, ydelta = 50;
  var isStandalone = false;
  var factor = 0.50;
  var f = [new sinSin (this),
           new sinExp (this),
           new squareSins (this),
           new randomPoints (this),
           new ellipse (this),
           new dataLoader (this),
           new harmonographCalculator (this)];

  var min = new Array (0.0, -2.9999, -4.9999, 0.1, 0.0, 0.0, 0.0);
  var max = new Array (50.0, 3.0, 5.0, 3.0, 0.0, 0.0, 100.0);
  var n = new Array (5000, 500, 500, 500, 500, 500, 10000);
  this.isXcrossing = [true, true, false, false, true, false, true];
  this.isYcrossing = [true, true, false, false, true, false, true];
  this.isXgrid = [false, false, false, true, false, false, false];
  this.isYgrid = [false, false, false, true, false, false, false];
  var iFunc = 1;
  var functions = new Array ("y = sin x + 5 * sin 10 x", 
                             "y = sin x * exp -5x^2", 
                             "y = (sin x)^2 + (sin 5x)^2", 
                             "arbitrary points", 
                             "Ellipse (a = 0.5, b = 1.5)", 
                             "loaded time series",
                             "Harmonograph");
  var EditFieldVector = null;
  var p2d = new plot2d (id, width, height, fill, opacity);
  var graphPanel = null;
  var dataTag = null;
  var editDataTagId = 'editDataWorkPlace';
  var editDataTag = null;
  var dialog = null;
  document.annimationId = 0;
  this.canvas = null;
  this.isDataEditVisible = false;
  this.isHeaderVisible = true;
  this.isPanelVisible = true;

//  -------------------------------------------------------------------------->
  this.resetParams = function (){
    this.isXaxisVisible = true;
    this.isYaxisVisible = true; 
    emptyTag (editDataTag);
  };

//  -------------------------------------------------------------------------->
  createDialog = function (containerID) {

    editDataTag = createDataEditTag  (editDataTagId);
    graphPanel = new GraphPanel ('1');
    dialog = document.getElementById (containerID);
    var dialogPanel = new Panel ('Dialog', 'dialog'); dialog.appendChild(dialogPanel);

    var header = new Header ('1', "draw your function"); dialogPanel.appendChild(header); header.ondblclickAction = function () {header.toggleHeight(header)}; 
    var minMaxPanel = new Panel ('MinMax'); dialogPanel.appendChild(minMaxPanel); 

    var funcCombo = new Combo ('function', functions, iFunc, '1'); funcCombo.onchangeAction = function () {document.chartNode.funcComboUpdateFunction (funcCombo)};
    minMaxPanel.appendChild (funcCombo);

    var minField = new Field ('min', 'min.: ', min[iFunc]); minField.onchangeAction = function () {document.chartNode.updateFunction (minField)};
    minMaxPanel.appendChild (minField);

    var maxField = new Field ('max', 'max.: ', max[iFunc]); maxField.onchangeAction = function () {document.chartNode.updateFunction (maxField)};
    minMaxPanel.appendChild (maxField);

    var numField = new Field ('n', 'number: ', n[iFunc]); numField.onchangeAction = function () {document.chartNode.updateFunction (numField)}; 
    minMaxPanel.appendChild (numField);
    
    var buttonPanel = new Panel ('Button'); dialogPanel.appendChild(buttonPanel);
    buttonPanel.appendHeader ('actions:');

    buttonPanel.appendChild (new Button ("flush", "flush", function () {document.chartNode.remove ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("update", "update", function () {document.chartNode.updateFunction ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("zoomIn", "zoom in", function () {zoomInFunction ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("zoomOut", "zoom out", function () {zoomOutFunction ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("animate", "animate", function () {animateFunction ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("regression", "regression", function () {regLineFunction ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("drawGrid", "draw grid", function () {document.chartNode.drawGridFunction ()})).firstChild.nodeValue = this.isXgrid ? 'no grid' : 'draw grid';
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("drawAxis", "no axis", function () {document.chartNode.drawAxisFunction ()})).firstChild.nodeValue = this.isXaxisVisible ? 'no axes' : 'draw axes';
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("editData", "edit data", function () {editDataFunction ()})).firstChild.nodeValue = this.isDataEditVisible ? 'hide data' : 'edit data';
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("userFunction", "user function", function () {userFunctionFunction ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    buttonPanel.appendChild (new Button ("savePNG", "save as PNG", function () {savePNGFunction ()}));
    buttonPanel.appendChild (document.createElement ('br'));

    var optionsPanel = new Panel ('Options'); dialogPanel.appendChild(optionsPanel);
    optionsPanel.appendHeader ('options:');
  };

//  -------------------------------------------------------------------------->
  this.getChart = function () {
    return chart;
  };

//  -------------------------------------------------------------------------->
  GraphPanel = function (id) {
    return p2d.getGraphics().getCanvas(); 
  };

//  -------------------------------------------------------------------------->
  this.getWorldGraphics = function () {
    return p2d; 
  };

//  ----------------------------------------------------------------------------
  this.calc = function (i, min, max, n) {
    return f[i].calc (min, max, n);
  }; 


//  ----------------------------------------------------------------------------
  this.draw = function (i, x, y) {
    if (!chart) chart = new Chart (p2d);
    chart.set (x, y, n,
               this.isXcrossing[iFunc], 
               this.isYcrossing[iFunc], 
               functions [i],
               "x", // text for x-Axis
               "y", // text for y-Axis
               i== 3 ? 3 : 0, // symbol type
               1, // symbol size
               i== 3 ? 0 : 1, // linetype
               this.isXgrid[iFunc], 
               this.isYgrid[iFunc]);
    if (i==1) 
      chart.setColors ('black', 'white', 'rainbow', 'red', 'gray');
    else
      chart.setColors ('white', 'black', 'blue', 'red', 'gray');
//    alert ('now draw: '+chart.toString());
    chart.draw ();
    return this;	
  }

//  ---------------------------------------------------------------------------
  this.funcComboUpdateFunction = function  () {
    var iFunc = document.forms.functioncombo.selection.options.selectedIndex;
    this.updateForm  (min[iFunc], max[iFunc], n[iFunc]);
    this.updateFunction ();
  };

//  ---------------------------------------------------------------------------
  this.updateFunction = function  () {
    this.remove (); 
    this.drawFunction ();
  };

//  ---------------------------------------------------------------------------
  this.drawFunction = function  () {
    this.resetParams ();
    iFunc = document.forms.functioncombo.selection.options.selectedIndex;
    this.calc (iFunc, 
               nodeOf ('inputmin').value, 
               nodeOf ('inputmax').value, 
               nodeOf ('inputn').value);
    this.draw (iFunc, f[iFunc].getX(), f[iFunc].getY());
  };

//  ---------------------------------------------------------------------------
  this.updateForm = function  (min, max, n) {
    if (min) nodeOf ('inputmin').value = min.toString();
    if (max) nodeOf ('inputmax').value = max.toString(); 
    if (n)   nodeOf ('inputn').value = n;
    return this;
  };

//  ---------------------------------------------------------------------------
  this.saveForm = function () {
    if (this.isSaved) return this;
    this.saveMin = nodeOf ('inputmin').value;
    this.saveMax = nodeOf ('inputmax').value; 
    this.saveN   = nodeOf ('inputn').value;
    this.isSaved = true;
    return this;
  };

//  ---------------------------------------------------------------------------
  this.restoreForm = function () {
    if (!this.isSaved) return this;
    nodeOf ('inputmin').value = this.saveMin;
    nodeOf ('inputmax').value = this.saveMax; 
    nodeOf ('inputn').value = this.saveN;
    this.isSaved = false;
    return this;
  };

//  ---------------------------------------------------------------------------
  editDataFunction = function  () {
    this.isDataEditVisible = !this.isDataEditVisible;
    document.getElementById ('buttoneditData').firstChild.nodeValue = this.isDataEditVisible ? 'hide data' : 'edit data';
    if (!editDataTag) 
      editDataTag = createDataEditTag (editDataTagId);
    editDataTag.style.display = (this.isDataEditVisible ? 'block' : 'none');
    graphPanel.style.display = (this.isDataEditVisible ? 'none' : 'block');
    if (!editDataTag.hasChildNodes())
      fillEditDataTag (editDataTag, f[iFunc].getX (), f[iFunc].getY ());
    if (!this.isDataEditVisible) {
      chart.remove ();
      chart.draw (p2d, f[iFunc].getX (), f[iFunc].getY ());
    }
    return this;
  };

//  ---------------------------------------------------------------------------
  createDataEditTag= function  (id) {
  //  traceln ('createDataEditTag ('+id+')');
    var container = document.createElement("div");
	container.className = 'editData';
    container.setAttribute("id", id);
    document.body.appendChild(container);
    return container;
  };

//  ---------------------------------------------------------------------------
  fillEditDataTag = function(tag, x, y) {
//    alert ('now fillEditDataTag ('+tag.id+')');
    if (!tag) return tag;
    var line, elx, ely, lNo;
    for (var i=0; i < x.length; i++) {
      line = document.createElement("div");
      line.id = 'line'+i;
      line.onclick = function () {editLine(this)};
      lNo = document.createElement("span"); lNo.appendChild (document.createTextNode (i));
      elx = document.createElement("span"); elx.appendChild (document.createTextNode (x[i].toString()));
      ely = document.createElement("span"); ely.appendChild (document.createTextNode (y[i].toString()));
      line.appendChild (lNo);
      line.appendChild (elx);
      line.appendChild (ely);
      tag.appendChild (line);
    }
    return tag;
  };

//  ---------------------------------------------------------------------------
  editLine = function (tag) {
    if (!tag) return tag;
    tag.onclickSave = tag.onclick;
    tag.onclick = function () {updateLine(tag)};
    var lValue = tag.firstChild.firstChild.nodeValue;
    var xValue = tag.firstChild.nextSibling.firstChild.nodeValue;
    var yValue = tag.lastChild.firstChild.nodeValue;
//    alert (tag.id+', '+lValue+', '+xValue+', '+yValue);
    var lNo = document.createElement("input"); lNo.value = lValue;
    var elx = document.createElement("input"); elx.value = xValue;
    var ely = document.createElement("input"); ely.value = yValue;
    var line = document.createElement("div");
    line.onchange = function () {updateLine(tag)};
    line.appendChild (lNo);
    line.appendChild (elx);
    line.appendChild (ely);
    setChildDisplay (tag, 'none', 3);
    tag.appendChild (line);
    return tag;
  };

//  ---------------------------------------------------------------------------
  updateLine = function (tag) {
    var x = f[iFunc].getX ();
    var y = f[iFunc].getY ();
    if (!tag) return tag;
    var inputLine = tag.lastChild;
    tag.childNodes[0].firstChild.nodeValue = inputLine.childNodes[0].value;
    tag.childNodes[1].firstChild.nodeValue = inputLine.childNodes[1].value;
    tag.childNodes[2].firstChild.nodeValue = inputLine.childNodes[2].value;
    var i = inputLine.childNodes[0].value;
    x[i] = inputLine.childNodes[1].value;
    y[i] = inputLine.childNodes[2].value;
    f.setX (x);
    f.setY (y);
    tag.removeChild(tag.lastChild);
    setChildDisplay (tag, 'inline', 3);
    tag.onclick = tag.onclickSave;
//    chart.draw (p2d, x,y);
    return tag;
  };

//  ---------------------------------------------------------------------------
  setChildDisplay = function (tag, value, n) {
    if (!tag) return tag;
    n = n==undefined ? tag.childNodes.length : n;
    for (var i=0; i < n; i++)
      tag.childNodes[i].style.display = value;
    return tag;
  };

//  ---------------------------------------------------------------------------
  emptyTag = function(tag) {
//    alert ('now emptyTag ('+tag.id+')');
    if (!tag) return this;
    while (tag.hasChildNodes())
      tag.removeChild(tag.lastChild);
    return this;
  };

//  ---------------------------------------------------------------------------
  userFunctionFunction = function  () {
    alert ('userFunction is not yet implemented'); 
  };

  //  ---------------------------------------------------------------------------
  zoomInFunction = function  () {
    var factor = chart.getFactor ()*StandardFactor;
    return p2d.resize  (p2d, factor);
//     chart.setFactor (p2d, factor);
  };

  //  ---------------------------------------------------------------------------
  zoomOutFunction = function  () {
    var factor = chart.getFactor ()/StandardFactor;
    return p2d.resize  (p2d, factor);
//     chart.setFactor (factor);
  };

  //  ---------------------------------------------------------------------------
  savePNGFunction = function  () {
    alert ('savePNGFunction not yet implemented'); 
//    handleSaveAction (imageIO.pngExt);
  }

  //  ---------------------------------------------------------------------------
  regLineFunction = function () {
    chart.drawRegressionLine ();  
  };

  //  ---------------------------------------------------------------------------
  this.drawGridFunction = function () {
    this.remove (); 
    this.isXgrid[iFunc] = !this.isXgrid[iFunc];
    this.isYgrid[iFunc] = !this.isYgrid[iFunc];
    this.drawFunction ();
    document.getElementById ('buttondrawGrid').firstChild.nodeValue  = this.isXgrid[iFunc] ? 'no grid' : 'draw grid';
  };

  //  ---------------------------------------------------------------------------
  this.drawAxisFunction = function () {
    this.isXaxisVisible = !this.isXaxisVisible;
    this.isYaxisVisible = !this.isYaxisVisible;
    chart.showAxes (this.isXaxisVisible, this.isYaxisVisible); 
    document.getElementById ('buttondrawAxis').firstChild.nodeValue  = this.isXaxisVisible ? 'no axes' : 'draw axes';
  };

  //  ---------------------------------------------------------------------------
  animateFunction = function  () {
//   alert ('now animate the graph');
//    chart.animationId = setInterval("alert ('red')", '100');  // And do this again after repeatTime [1/1000 sec];
    chart.animationId = setInterval("document.chart.drawAnimatedSymbols ('red')", '100');  // And do this again after repeatTime [1/1000 sec];
  };

//  ---------------------------------------------------------------------------
  handleSaveAction = function  (ext) {
    if (wordy) alert  ("ActionCommand save as "+ext+" erhalten!");
    var name = new String("img/"+ delChar (functions [iFunc], " ,.-+()[]/*=^")+ext);
    if (wordy) alert ("name ="+name);
    graphPanel.p2d.save(name);
  }

//  ----------------------------------------------------------------------------
  this.remove = function () {
    if (!chart) return null;
    chart.remove ();
//    chart = null;
    return this;
  }

//  ----------------------------------------------------------------------------
  this.maximize = function () {
    alert ('ChartTest.maximize() not yet implemented!'); 
//    var usableWidth = d.width - i.left - i.right - frame.getBounds().x - xdelta; ; 
//    var usableHeight = d.height - i.top - i.bottom - frame.getBounds().y - ydelta;  
  }

//  ---------------------------------------------------------------------------
  getData = function(docURL, name, postAction) {
    var id = "dataBox";
    if (!postAction) postAction = function () {};
    var sourceURL = getSelfDomain ()+'/data/'+name;
//    alert ('sourceURL:'+sourceURL);
    var dataTag = document.getElementById (id);
    if (dataTag == null) {
      var header = document.getElementById ('header1');
      header.saveText();
      header.setText('loading ...');
      header.style.textDecoration = 'blink';
      header.style.color = 'red';
      dataTag = createDataTag (id);
      loadToID(sourceURL, id, postAction);
    } else {
      emptyTag (dataTag);
      postAction();
    }
  };

//  ---------------------------------------------------------------------------
/*  this.save = function (v) {
    this.v = v;
    return this;
  };*/

//  ---------------------------------------------------------------------------
/*  this.restore = function () {
    return this.v;
  };*/

//  ---------------------------------------------------------------------------
  createDataTag= function  (id) {
  //  traceln ('createcontainer ('+id+')');
    var container = document.createElement("div");
    container.innerHTML = id;
    container.setAttribute("id", id);
    container.style.backgroundColor= "white";
    container.style.border= "1px solid red";
    container.style.borderBottom= "1px solid aqua";
    container.style.visibility = "hidden" ;
    container.style.display = "none" ;
    document.body.appendChild(container);
    return container;
  };

//  ----------------------------------------------------------------------------
  this.init = function () {
    this.resetParams ();
    createDialog('dialog');
    if (!p2d) return null;
    this.drawFunction ();
    document.dragger = new Drag();
    document.dragger.init('header1', 'panelDialog');
    return this;
};

//  ----------------------------------------------------------------------------
}

//  ---------------------------------------------------------------------------->
function show (id, text) {
  //  alert ("show ("+id+" : "+text+")");
  var node = document.getElementById(id).firstChild;
  node.nodeValue = text === undefined ? '' : id + ': '+text;
  return node;
}

//  ----------------------------------------------------------------------------
function transformData (ref) {
//  alert ('transformData ('+ref.id+') working ...');
  var dataTag = nodeOf ('dataBox');
  if (dataTag) {
    if (dataTag.hasChildNodes()) {
      var x = new Array(0);
      var y = new Array(0);
      var j = 0;
      for (var i=0; i < dataTag.childNodes.length; i++) {
        if (dataTag.childNodes[i].nodeName.toLowerCase() == 'div') {
//          show ('trace',j+'('+i+'): elements read, last = '+dataTag.childNodes[i].firstChild.firstChild.nodeValue);
          x[j] = new Date().fromString (dataTag.childNodes[i].firstChild.firstChild.nodeValue);
          y[j++] = dataTag.childNodes[i].lastChild.firstChild.nodeValue;
        } 
      }
//      alert ('now set x and y to '+ref.id);
      ref.setX(x).setY(y);
//      alert (ref.getX().toString()+', '+ref.getY().toString());
//      alert ('ref.caller= '+ref.caller.id);
      ref.caller.updateForm (x[0], x[x.length-1], x.length);
//      alert('next stop here');
      ref.caller.getChart().set(x, y).draw(); //  alert (toString()); 
      var header = nodeOf ('header1');
//      alert (header.id);
      header.restoreText();
      header.style.textDecoration = 'none';
      header.style.color = 'black';
    }
  }
//  alert ('leaving transformData ('+ref.id+') ...');
  return ref;
}

//  ----------------------------------------------------------------------------
function sinSin () { 
  this.id = 'sinSin';
}

sinSin.prototype = new functionCalculator ();

//  ----------------------------------------------------------------------------
sinSin.prototype.calcPoint = function (xi, i) {
  return Math.sin(xi) + 5 * Math.sin(10 * xi);
};

//  ----------------------------------------------------------------------------
function sinExp () { 
  this.id = 'sinExp';
}

sinExp.prototype = new functionCalculator ();

//  ----------------------------------------------------------------------------
sinExp.prototype.calcPoint = function (xi, i) {
  return Math.cos(5 * xi) * 5 * Math.exp(-xi * xi);
};

//  ----------------------------------------------------------------------------
function squareSins () { 
  this.id = 'squareSins';
}

squareSins.prototype = new functionCalculator ();

//  ----------------------------------------------------------------------------
squareSins.prototype.calcPoint = function (xi, i) {
  return Math.sin(xi) * Math.sin(xi) + Math.sin(5 * xi) * Math.sin(5 * xi);
};

//  ----------------------------------------------------------------------------
function randomPoints () { 
  this.id = 'randomPoints';
  var wordy = false;
  if (wordy) {alert ('randomPoints created');}
}

randomPoints.prototype = new functionCalculator ();

//  ----------------------------------------------------------------------------
randomPoints.prototype.calcPoint = function (xi, i) {
  return Math.random() / xi;
};

//  ----------------------------------------------------------------------------
function ellipse () { 
  this.id = 'ellipse';
  this.ax = 0.3;
  this.bx = 0.0;
  this.ay = 0.5;
  this.by = 0.0;
}

ellipse.prototype = new functionCalculator ();

//  ----------------------------------------------------------------------------
ellipse.prototype.calc = function (min, max, n) {
  xAct = parseFloat(min, 10);
  xInc = 2 * Math.PI / parseFloat(n, 10);
  for (var i = 0; i < parseInt(n, 10); i++) {
    this.x[i] = Math.sin(xAct) * this.ax + this.bx; 
    this.y[i] = Math.cos(xAct) * this.ay + this.by;
    xAct += xInc;
  }
  return this;
};

//  ----------------------------------------------------------------------------
function dataLoader (caller) { 
  this.id = 'dataLoader';
  this.caller = caller;
}

dataLoader.prototype = new functionCalculator ();

//  ----------------------------------------------------------------------------
dataLoader.prototype.calc = function (min, max, n) {
  var fileName = 'abf.xhtml';
  if (this.loadFileName != fileName) {
    this.loadFileName == fileName;
    var ref = this;
    var func = function () {
      transformData(ref);
    };
    getData(window.location.pathname, fileName, func);
  } else alert (this.id+'.calc: no calculatiuon');
  return this;
};

//  ----------------------------------------------------------------------------
function harmonographCalculator () { 
  this.id = 'harmonographCalculator';
  this.f1 = 2;
  this.f2 = 2;
  this.f3 = 2;
  this.f4 = 2;
  this.p1 = 1/16;
  this.p2 = 3/2;
  this.p3 = 13/15;
  this.p4 = 1;
  this.d1 = 0.02;
  this.d2 = 0.0315;
  this.d3 = 0.02;
  this.d4 = 0.02;
}

harmonographCalculator.prototype = new functionCalculator ();

//  ----------------------------------------------------------------------------
harmonographCalculator.prototype.calc = function (min, max, n) {
  this.f1 = (this.f1 + Math.random() / 40) % 10;
  this.f2 = (this.f2 + Math.random() / 40) % 10;
  this.f3 = (this.f3 + Math.random() / 40) % 10;
  this.f4 = (this.f4 + Math.random() / 40) % 10;
  this.p1 += 0.05 % (Math.PI*2)
  xAct = parseFloat(min, 10);
  xInc = (parseFloat(max, 10) - parseFloat(min, 10)) / parseFloat(n, 10);
  for (var i = 0; i < parseInt(n, 10); i++) {
    this.x[i] = Math.sin(this.f1 * xAct + Math.PI * this.p1) * Math.exp(-this.d1 * xAct) + Math.sin(this.f2 * xAct + Math.PI * this.p2) * Math.exp(-this.d2 * xAct);
    this.y[i] = Math.sin(this.f3 * xAct + Math.PI * this.p3) * Math.exp(-this.d3 * xAct) + Math.sin(this.f4 * xAct + Math.PI * this.p4) * Math.exp(-this.d4 * xAct);
    xAct += xInc;
  }
  return this;
};

//  ----------------------------------------------------------------------------
harmonographCalculator.prototype.calcPoint = function (xi, i) {
  return yi;
};
