//  ----------------------------------------------------------------------------
function DateTimeScaler(min, max, viewLen) {
  this.id = 'DateTimeScaler';
  var wordy = false;
  this.yearInc = 0;
  this.level = 9;
  this.zeroTime = new Date(0);
  this.init(min, max, viewLen);
}

DateTimeScaler.prototype = new Scaler ();

//DateTimeScaler.inherits(Scaler);

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.getPlaces = function () {
//  var b = new Date(this.min).getBounds(new Date(this.max));
//  alert (b[0]+', '+b[1]);
  return (new Date(this.min).getBounds(new Date(this.max)))
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.init = function(min, max, viewLen) {
  this.setLevel(0);
  this.initScaler(min, max, viewLen);
  return this;
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.setLevel = function(level) {
  this.level = level;
  return this;
};  

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.getLevel = function() {
  return this.level;
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.calcLevel = function(min, max) {
  return (new Date(min).changeLevel(new Date(max)))
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.autoScale = function(min, max, viewLen) {
  min = isDate(min) ? min : (isString(min)? new Date ().fromString(min) : new Date().setTime(min));
  max = isDate(max) ? max : (isString(max)? new Date ().fromString(max) : new Date().setTime(max));
//  alert (this.id+'.autoScale_1 ('+min+', '+max+', '+viewLen+')');
  var wordy = false;
  this.min = min==undefined || (!isDate(min)) ? this.min : min.copy();
  this.max = max==undefined || (!isDate(max)) ? this.max : max.copy();
  this.viewLen = viewLen==undefined ? this.viewLen : viewLen;
  var zeroTime = new Date(0);
  var minTime = this.min;
  var maxTime = this.max;
  if (wordy) alert(this.id+'.autoScale_2('+minTime.toString()+', '+maxTime.toString()+', '+this.viewLen+')');

  var dateDiff = minTime.age(maxTime);
  this.level = minTime.changeLevel(maxTime);
  if (wordy) alert("dateDiff=(" + dateDiff[0] + " sec., " + dateDiff[1] + " min., " + dateDiff[2] + " hours, "  + dateDiff[3] + " days, " + dateDiff[4] + "months, " + dateDiff[5]+" years), date change occurred (" + minTime + ", " + maxTime + ") = #" + this.level);
  switch (this.level) {
    case zeroTime.SECONDS:        { // seconds
      if (wordy) alert('time change is: '+dateDiff[zeroTime.SECONDS]+' seconds: ' + minTime.changeLevel(maxTime));
      this.valMin = minTime.getTime();
      this.valMax = maxTime.getTime();
      this.nValInc = minTime.seconds(maxTime);
//      while (this.nValInc >= 15) this.nValInc /= 5;
      this.valInc = Math.abs((this.valMax - this.valMin) / this.nValInc);
      break;
    }
    case zeroTime.MINUTES:        { // minutes
      if (wordy) alert('time change is: '+dateDiff[zeroTime.MINUTES]+' minutes: ' + minTime.changeLevel(maxTime)+'('+minTime+' --> '+maxTime+')');
      minTime.setSeconds (0);
      maxTime.addMinutes(maxTime.getSeconds() ? 1 : 0);
      maxTime.setSeconds (0);
      this.valMin = minTime.getTime();
      this.valMax = maxTime.getTime();
      this.nValInc = minTime.minutes(maxTime);
//      while(this.nValInc >= 15) this.nValInc /= 5;
      this.valInc = (Math.abs(this.valMax - this.valMin)) / this.nValInc;
      if (wordy) alert(minTime.toString(this.level)+' to '+maxTime.toString(this.level)+' --> '+this.valMin+' to '+this.valMax+', nValInc = '+this.nValInc+' * valInc = '+this.valInc);
      break;
    }
    case zeroTime.HOURS:        { // hours
      if (wordy) alert('time change is: '+dateDiff[zeroTime.HOURS]+' hours: ' + minTime.changeLevel(maxTime));
      minTime.setMinutes(0);
      minTime.setSeconds(0);
      maxTime.addHours((maxTime.getMinutes() || maxTime.getSeconds()) ? 1 : 0);
      maxTime.setMinutes(0);
      maxTime.setSeconds(0);
      this.valMin = minTime.getTime();
      this.valMax = maxTime.getTime();
      this.nValInc = minTime.hours(maxTime);
//      while (this.nValInc >= 15) this.nValInc /= 5;
      this.valInc = (Math.abs(this.valMax - this.valMin)) / this.nValInc;
      if (wordy) alert(minTime.toString(this.level)+' to '+maxTime.toString(this.level)+' --> '+this.valMin+' to '+this.valMax+', nValInc = '+this.nValInc+' * valInc = '+this.valInc);
      break;
    }
    case zeroTime.DAYS:    { // age in days.
      if (wordy) alert("date change is: " + dateDiff[zeroTime.DAYS] +' days: ' + minTime.changeLevel(maxTime));
      minTime.setMinutes(0);
      minTime.setSeconds(0);
      minTime.setHours(0);
      maxTime.addDays((maxTime.getHours() || maxTime.getMinutes() || maxTime.getSeconds()) ? 1 : 0);
      maxTime.setMinutes(0);
      maxTime.setSeconds(0);
      maxTime.setHours(0);
      this.valMin = minTime.getTime();
      this.valMax = maxTime.getTime();
      this.nValInc = minTime.days(maxTime);
      this.valInc = (Math.abs(this.valMax - this.valMin)) / this.nValInc;
      break;
    }
    case zeroTime.MONTHS:    { // age in months
      if (wordy) alert('DateTimeScaler.autoScale('+minTime.toString()+', '+maxTime.toString()+', '+this.viewLen+')');
      if (wordy) alert("date change is: " + dateDiff[zeroTime.MONTHS]+' months, level= ' + minTime.changeLevel(maxTime));
      this.valMin = new Date(minTime.getFullYear(), minTime.getMonth(), 1).getTime();
      this.valMax = new Date(maxTime.getFullYear(), maxTime.getMonth(), maxTime.daysInMonth ()).addDays(1).getTime();
      this.nValInc = new Date(this.valMin).months(new Date(this.valMax));
      this.valInc = (Math.abs(this.valMax - this.valMin)) / this.nValInc;
      if (wordy) alert(minTime.toString()+' to '+maxTime.toString()+' --> '+this.valMin+' to '+this.valMax+', nValInc = '+this.nValInc+' * valInc = '+this.valInc);
      break;
    }
    case zeroTime.YEARS:    { // age in years
      if (wordy) alert("date change is: " + dateDiff[zeroTime.YEARS] + ' years: ' + minTime.changeLevel(maxTime));
      this.yearInc = this.getDiffDimension (minTime.getFullYear(), maxTime.getFullYear()); // alert ('yearInc: '+this.yearInc);
      this.valMin = new Date(this.lower  (minTime.getFullYear(), maxTime.getFullYear()),  0,  1).getTime();
      this.valMax = new Date(this.higher (minTime.getFullYear(), maxTime.getFullYear()), this.yearInc > 1 ? 0 : 11, this.yearInc > 1 ? 1 : 31).addDays(this.yearInc > 1 ? 0 : 1).getTime();
      this.nValInc = Math.floor (new Date(this.valMin).years(new Date(this.valMax)) / this.yearInc); // +(this.yearInc > 1 ? 0 : 1);
      this.valInc = (Math.abs(this.valMax - this.valMin)) / this.nValInc;
      if (wordy) alert(minTime.toString(this.level)+' to '+maxTime.toString(this.level)+' --> '+this.valMin+' to '+this.valMax+', nValInc = '+this.nValInc+' * valInc = '+this.valInc);
      break;
	}  
    default: {
      alert ('###  err: '+this.id+'.autoScale ('+min+', '+max+', '+viewLen+'), no time change:'+this.level+". Can't draw no axis!");
      return this;
    }
  }
  this.scalingFactor = this.viewLen / (this.valMax - this.valMin);
  if (wordy) alert(this.toString());
  if (new Date(this.valMax).toString()  != new Date(this.calcValue (this.nValInc)).toString()) 
    alert ('###  err: '+this.id+'.autoScale: '+this.level+': valMax ('+(new Date(this.valMax)).toString() + ') != n * inc ('+ new Date(this.calcValue (this.nValInc)).toString()+'), test: length ('+this.viewLen+') == n * paper inc ('+ (this.scalingFactor * (this.valMax - this.valMin))+') ?');
  return this;
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.getDiffDimension = function(min, max) {
  for (var fac = 1; Math.floor((max - min) / fac) > 0; fac *= 10);
//  alert ('DateTimeScaler.getDiffDimension: '+(fac/10));
  return fac/10;
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.lower = function(min, max) {
  var fac = this.getDiffDimension(min, max);
  return Math.floor (min/fac)*fac;
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.higher = function(min, max) {
  var fac = this.getDiffDimension(min, max);
//  alert (this.id+'.higher ('+min.toString()+', '+max.toString()+') --> '+(-(Math.floor (-max/fac)*fac)));
  return -(Math.floor (-max/fac)*fac);
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.manualScale = function(min, max, inc) {
  if (wordy) alert("" + 'DateTimeScaler' + ".manualScale ...");
  this.valMin = min;
  this.valMax = max;
  this.valInc = inc;
  this.nValInc = Math.floor((this.valMax - this.valMin) / this.valInc);
  this.scalingFactor = this.viewLen / (this.valMax - this.valMin);
  if (max <= min) alert("### err: " + 'DateTimeScaler' + ".manualScale: max <= min");
  return this;
};

//  --------------------------------------------------------------------------->
DateTimeScaler.prototype.calcValue = function (i) {
//  alert (this.id+'.calcValue('+i+')');
  switch (this.getLevel()) {
    case this.zeroTime.SECONDS: { // seconds
      return (new Date (this.getValMin())).addSeconds(i).getTime();
      break;
    }
    case this.zeroTime.MINUTES: { // minutes
      return (new Date (this.getValMin())).addMinutes(i).getTime();
      break
    }
    case this.zeroTime.HOURS:  { // hours
      return (new Date (this.getValMin())).addHours(i).getTime();
      break;
    }
    case this.zeroTime.DAYS: { // days
      return (new Date (this.getValMin())).addDays(i).getTime();
      break;
    }
    case this.zeroTime.MONTHS: { // months
      return (new Date (this.getValMin())).addMonths(i).getTime();
      break;
    }
    case this.zeroTime.YEARS: { // years
      return (new Date (this.getValMin())).addYears(i * this.getYearInc()).getTime();
      break;
    }
    default:  {
      alert ('###  '+this.id+'.calcValue: no valid value of "level": '+this.getLevel())
      break;
    }
  }
};

//  --------------------------------------------------------------------------->
/*DateTimeScaler.prototype.scaleValue = function(v) {
  alert(this.id + ".scaleValue = " + (v - this.valMin) * this.scalingFactor + " = " + v + "-" + this.valMin + ") * " + this.scalingFactor);
  return (v - this.valMin) * this.scalingFactor;
};*/

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.toString = function() {
  return 'DateTimeScaler : Min : ' +(new Date(this.valMin)).toString(this.level) + ", Max : " +  (new Date(this.valMax)).toString(this.level) + ", increment = " + this.valInc + " * " + this.nValInc + ", scaling factor = " + this.scalingFactor;
};

//  ----------------------------------------------------------------------------
DateTimeScaler.prototype.getYearInc = function () {
  return this.yearInc;
};

//  ----------------------------------------------------------------------------
