  window.calculator = {}
  
  /**
   * Показывать ли цены объектов
   */
  window.calculator.showObjectPrices = false;
  
  window.calculator.levelLabels = [
    'Вид оценки',
    'Вид объекта',
    'Подвид объекта',
    'Характеристики'
  ];
  
  window.calculator.init = function (containerId, tree) {
    this.objects = [];
    this.tree = tree;
    this.coefficients = [];
    this.sameTypeCoefficient = null;
    this.totalPrice = 0;
    
    this.cursorOverContext = false;
    
    for (var i in this.tree.coefficients)
      if (this.tree.coefficients[i].forSameType == 1)
        this.sameTypeCoefficient = this.tree.coefficients[i];
      else
        this.coefficients.push (this.tree.coefficients[i]);

    this.containerId = containerId;
    this.container = $('#' + containerId);
    
    this.objectsWrapperId = this.id ('objectsWrapper');
    this.controlsWrapperId = this.id ('controlsWrapper');
    this.contextId = this.id ('context');
    this.totalPriceWrapperId = this.id ('totalPriceWrapper');
    
    this.container.html ([
      '<div id="' + this.contextId + '"></div>',
      '<div id="' + this.objectsWrapperId + '"></div>',
      '<div id="' + this.controlsWrapperId + '">',
        '<a href="#" class="buttonLink" onclick="window.calculator.addObject (); return false;">Добавить новый объект</a>',
        '<div id="' + this.totalPriceWrapperId + '" style="color: #B20021; font-size: 23px; float: right;">',
        '</div>',
      '</div>',
      '<div style="margin-top: 20px; font-size: 10px;">',
        '<p>В стоимости работ не учтен выезд оценщика на осмотр.</p>',
        '<p>Стоимость и сроки выполнения работ могут быть изменены в соответствии с вновь выявленными обстоятельствами при регистрации заявки.</p>',
        '<p>Минимальная стоимость одного отчета 2000 рублей</p>',
      '</div>'
    ].join (''));

    this.objectsWrapper = $('#' + this.objectsWrapperId);
    this.controlsWrapper = $('#' + this.controlsWrapperId);
    this.context = $('#' + this.contextId);
    this.totalPriceWrapper = $('#' + this.totalPriceWrapperId);
    
    this.context.bind ('mouseover', this.contextOver).bind ('mouseleave', this.contextOut);
  }
  
  window.calculator.id = function (id) {
    return this.containerId + '_' + id;
  }
  
  window.calculator.addObject = function () {
    this.objects.push ({
      name: '',
      levels: [],
      coefficients: [],
      price: 0,
      //originalPrice: 0, // цена без коэффициентов
      additional: 0,
    });
    this.recalculate ();
    this.renderObjects ();
  }
  
  window.calculator.copyObject = function (index) {
    this.objects.push (this.clone (this.objects[index]));
    this.recalculate ();
    this.renderObjects ();
  }
  
  window.calculator.renderObjects = function () {
    var html = '';
    for (var i in this.objects)
      html += this.renderObject (i);
    this.objectsWrapper.html (html);
    this.totalPriceWrapper.html (this.priceToText (this.totalPrice, 'Суммарная цена'));
  }
  
  window.calculator.removeObject = function (index) {
    this.objects.splice (index, 1);
    this.recalculate ();
    this.renderObjects ();
  }
  
  window.calculator.renderObject = function (index) {
    var o = this.objects[index];
    var levelRows = time = coefficients = additional =  '';
    var strict = false;
    for (var i = 0; i <= o.levels.length; i++) {
      if (typeof o.levels[i] != 'undefined' && o.levels[i].type == 'item') {
        time = [
          '<tr>',
            '<td class="label">Срок выполнения:</td>',
            '<td>' + this.htmlspecialchars (this.daysToText (o.levels[i].time)) + '</td>',
          '</tr>',
        ].join ('');
        if (o.levels[i].unitSize != 0) {
          additional = [
            ' + ',
            '<input type="text" value="' + this.htmlspecialchars (o.additional) + '" onkeyup="window.calculator.objects[' + index + '].additional = this.value; window.calculator.recalculate (); window.calculator.refreshObjects (true);" style="width: 50px;" />'
          ].join ('');
        }
      }
      strict = typeof o.levels[i - 1] != 'undefined' && o.levels[i - 1].type == 'item';
      if (!strict)
        levelRows += [
          '<tr>',
            '<td class="label">' + this.levelLabels[i] + ':</td>',
            '<td>',
              '<a href="#" id="' + this.id ('level_' + index + '_' + i) + '" onclick="window.calculator.showLevels (' + index + ', ' + i + '); return false;">',
                this.htmlspecialchars (typeof o.levels[i] != 'undefined' ? o.levels[i].name : '(выбрать)'),
              '</a>' + additional,
            '</td>',
          '</tr>',
        ].join ('');
    }
    if (o.coefficients.length == 0) {
      coefficients = '(выбрать)';
    } else {
      for (var i = 0; i < o.coefficients.length; i++) {
        var coef = this.coefficients[o.coefficients[i]];
        coefficients += (i == 0 ? '' : '<br />') + coef.name;
      }
    }
    
    return [
      '<div class="calculatorObject" id="' + this.id ('object_' + index) + '">',
      
        '<div class="calculatorObjectRemove">',
          '<a href="#" class="buttonLink" onclick="window.calculator.removeObject (' + index + '); return false;">',
            'Удалить объект',
          '</a>',
        '</div>',
        
        '<table>',
          '<tr>',
            '<td class="label">Название объекта:</td>',
            '<td><input type="text" value="' + this.htmlspecialchars (o.name) + '" onkeyup="window.calculator.objects[' + index + '].name = this.value;" style="width: 250px" /></td>',
          '</tr>',
          levelRows,
          time,
          '<tr>',
            '<td class="label">Доп. условия:</td>',
            '<td><a href="#" id="' + this.id ('coefficients_' + index) + '" onclick="window.calculator.showCoefficients (' + index + '); return false;">' + coefficients + '</a></td>',
          '</tr>',
        '</table>',
        
        //additional,
        
        '<div class="calculatorObjectControls">',
          '<div class="calculatorObjectPrice">',
            this.showObjectPrices ? this.priceToText (o.price) : '',
          '</div>',
          '<a href="#" class="buttonLink" onclick="window.calculator.copyObject (' + index + '); return false;">',
            'Скопировать объект',
          '</a>',
        '</div>',
        
      '</div>'
    ].join ('');
  }
  
  window.calculator.priceToText = function (price, label) {
    label = typeof label != 'undefined' ? label : 'Цена';
    return price == 0 ? '' : label + ': ' + this.addCommas (price, ' ') + ' ' + this.pluralForm (price, [
      'рубль', 'рубля', 'рублей'
    ]);
  }
  
  window,calculator.daysToText = function (days) {
    return days + ' ' + this.pluralForm (days, [
      'день', 'дня', 'дней',
    ]);
  }
  
  window.calculator.showContext = function (linkSelector) {
    var link = $(linkSelector);
    var pos = link.position ();
    pos.top += link.height ();
    this.context.html ('').css (pos).fadeIn ('fast');
  }
  
  window.calculator.hideContext = function (veryFast) {
    if (veryFast)
      this.context.hide ();
    else
      this.context.fadeOut (150);
  }
  
  window.calculator.contextOver = function () {
    window.calculator.cursorOverContext = true;
  }
  
  window.calculator.contextOut = function () {
    var self = window.calculator;
    if (self.cursorOverContext) {
      self.hideContext ();
      self.cursorOverContext = false;
    }
  }
  
  window.calculator.refreshObject = function (index, pricesOnly) {
    if (typeof pricesOnly == 'undefined') {
      var newHtml = this.renderObject (index);
      $('#' + this.id ('object_' + index)).replaceWith (newHtml);
    } else {
      if (this.showObjectPrices) {
        $('#' + this.id ('object_' + index) + ' .calculatorObjectPrice').html (this.priceToText (this.objects[index].price));
      }
    }
  }
  
  window.calculator.refreshObjects = function (pricesOnly) {
    for (var i in this.objects)
      this.refreshObject (i, pricesOnly);
    this.totalPriceWrapper.html (this.priceToText (this.totalPrice, 'Суммарная цена'));
  }
  
  window.calculator.recalculate = function () {
    this.totalPrice = 0;
    for (var i = 0; i < this.objects.length; i++) {
      var o = this.objects[i];
      o.price = 0;
      var currentItem = this.getObjectItem (i);
      if (currentItem) {
        o.price = currentItem.price * 1;

        if (currentItem.unitSize != 0) {
          var realUnitPrice = currentItem.unitsPrice / currentItem.unitSize;
          o.price += o.additional * realUnitPrice;
        }

        for (var k in o.coefficients) {
          o.price *= this.coefficients[o.coefficients[k]].coefficient * 1;
        }

        if (i > 0) {
          var setSTC = false;
          for (var j = 0; j < i; j++) {
            var previousItem = this.getObjectItem (j);
            if (previousItem && previousItem.id == currentItem.id)
              setSTC = true;
          }
          if (setSTC)
            o.price *= this.sameTypeCoefficient.coefficient * 1;
        }
        
      }
      this.totalPrice += o.price = Math.round (o.price);
    }
  }
  
  window.calculator.getObjectItem = function (index) {
    var o = this.objects[index];
    var lastLevelItem = false;
    for (var j in o.levels)
      lastLevelItem = o.levels[j].type == 'item' ? o.levels[j] : false;
    return lastLevelItem;
  }
  
  window.calculator.showLevels = function (objectIndex, levelIndex) {
    var o = this.objects[objectIndex];
    var parentLevel = (levelIndex == 0) ? this.tree.priceListTree : o.levels[levelIndex - 1].childs;
    this.showContext ('#' + this.id ('level_' + objectIndex + '_' + levelIndex));
    var name = this.id ('levelOption_' + objectIndex + '_' + levelIndex);
    $.each (parentLevel, function (i, val) {
      var checked = (typeof o.levels[levelIndex] == 'undefined') ? false : (o.levels[levelIndex].id == val.id);
      var id = name  + '_' + i;
      var html = [
        '<div>',
          '<input type="radio"' + (checked ? ' checked="checked"' : '') + ' name="' + name + '" id="' + id + '" /><label for="' + id + '">' + window.calculator.htmlspecialchars (val.name) + '</label>',
        '</div>',
      ].join ('');
      window.calculator.context.append (html);
      $('#' + id).attr ('checked', checked).bind ('click', function () {
        window.calculator.switchLevel (objectIndex, levelIndex, parentLevel, i);
      });
    });
  }
  
  window.calculator.showCoefficients = function (objectIndex) {
    var o = this.objects[objectIndex];
    this.showContext ('#' + this.id ('coefficients_' + objectIndex));
    var name = this.id ('coefficientOption_' + objectIndex);
    for (var i in this.coefficients) {
      var id = name + '_' + i;
      var checked = false;
      for (var j in o.coefficients)
        if (o.coefficients[j] == i)
          checked = true;
      var html = [
        '<div>',
          '<input type="checkbox"' + (checked ? ' checked="checked"' : '') + ' onclick="window.calculator.setCoefficient (' + objectIndex + ', ' + i + ', this.checked)" name="' + id + '" id="' + id + '" />',
          '<label for="' + id + '">' + this.coefficients[i].name + '</label>',
        '</div>',
      ].join ('');
      $('#' + id).attr ('checked', checked);
      this.context.append (html);
    }
  }
  
  window.calculator.setCoefficient = function (objectIndex, coefficientIndex, value) {
    var o = this.objects[objectIndex];
    if (value) {
      var set = true;
      for (var i in o.coefficients)
        if (o.coefficients[i] == coefficientIndex)
          set = false;
      if (set)
        o.coefficients.push (coefficientIndex);
    } else {
      for (var i = 0; i < o.coefficients.length; i++)
        if (o.coefficients[i] == coefficientIndex)
          o.coefficients.splice (i, 1);
    }
    //this.refreshObject (objectIndex);
    this.recalculate ();
    this.refreshObjects ();
  }
  
  window.calculator.switchLevel = function (objectIndex, levelIndex, parentLevel, levelObjectIndex) {
    var o = this.objects[objectIndex];
    if (o.levels.length = levelIndex) {
      o.levels.push (parentLevel[levelObjectIndex]);
    } else {
      o.levels[levelIndex] = parentLevel[levelObjectIndex];
    }
    this.recalculate ();
    this.refreshObjects (); // везде, т.к. есть коэф. повторения
    if (parentLevel[levelObjectIndex].type == 'item') {
      this.hideContext (true);
      this.onItemSelect (o, parentLevel[levelObjectIndex]);
    } else {
      this.hideContext ();
    }
  }
  
  window.calculator.onItemSelect = function (object, item) {
    /*
     * Надоедливо спрашивать о дополнительных предметах оценки
     */
    var yes = false;
    if (object.levels.length >= 2) {
      var id = object.levels[1].id;
      if (id == 14) {
        if (yes = confirm ('Имеется ли на данном земельном участке строение как предмет оценки?'))
          this.addObject ();
      } else if (id == 16) {
        if (yes = confirm ('Имеется ли под данным строением (объектом) земельный участок как предмет оценки?'))
          this.addObject ();
      }
    }
    if (!yes && confirm ('Желаете ли добавить еще объект для оценки?'))
      this.addObject ();
  }
  
  window.calculator.pluralForm = function (number, forms) {
    return number % 10 == 1 && number % 100 != 11 ? forms[0] : (number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 10 || number %100 >= 20) ? forms[1] : forms[2]);
  }
  
  window.calculator.clone = function (o) {
    if (!o || 'object' !== typeof o)
      return o;
    var c = 'function' === typeof o.pop ? [] : {};
    var p, v;
    for (p in o) {
      if (o.hasOwnProperty (p)) {
        v = o[p];
        if (v && 'object' === typeof v)
          c[p] = this.clone (v);
        else
          c[p] = v;
      }
    }
    return c;
  }
  
  window.calculator.addCommas = function (number, comma) {
    comma = typeof comma == 'undefined' ? ',' : comma;
    number += '';
    var x = number.split ('.');
    var x1 = x[0];
    var x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test (x1))
      x1 = x1.replace (rgx, '$1' + comma + '$2');
    return x1 + x2;
  }
  
  window.calculator.submiting = false;
  window.calculator.submitForm = function () {
    if (!window.calculator.submiting) {
      if ($('#calculatorFormEmail').val ()) {
        window.calculator.submiting = true;
        $('label[for=calculatorFormEmail]').hide ();
        $('#calculatorFormAjax').show ();
        $('#calculatorFormSuccess').hide ();
        var lines = [];
        for (var i in window.calculator.objects) {
          var name = window.calculator.urlencode (window.calculator.objects[i].name);
          var levels = [];
          var time = '';
          for (var j in window.calculator.objects[i].levels) {
            levels.push (window.calculator.urlencode (window.calculator.objects[i].levels[j].name));
            time = window.calculator.objects[i].levels[j].time;
            time = typeof time == 'undefined' ? '' : window.calculator.urlencode (time);
          }
          var additional = window.calculator.urlencode (window.calculator.objects[i].additional);
          var coefficients = [];
          for (var j in window.calculator.objects[i].coefficients)
            coefficients.push (window.calculator.urlencode (window.calculator.coefficients[window.calculator.objects[i].coefficients[j]].name));
          var price = window.calculator.urlencode (window.calculator.objects[i].price);
          
          lines.push (name + '|' + levels.join ('/') + '|' + time + '|' + additional + '|' + coefficients.join ('/') + '|' + price);
        }
        $.post ('/calc/?send=1', {
          'objects[]': lines,
          'name': $('#calculatorFormName').val (),
          'phone': $('#calculatorFormPhone').val (),
          'email': $('#calculatorFormEmail').val (),
          'comment': $('#calculatorFormComment').val ()
        }, function (data) {
          if (data.err)
            window.alert ('Ошибка при отправке формы, попробуйте попытку позднее.');
          else {
            $('#calculatorFormAjax').hide ();
            $('#calculatorFormSuccess').show ();
            window.calculator.submiting = false;
          }
        }, 'json');
      } else {
        $('label[for=calculatorFormEmail]').show ();
        $('#calculatorFormEmail').focus ();
      }
    }
    return false;
  }
  
  /**
   * @see http://phpjs.org/functions/htmlspecialchars
   */
  window.calculator.htmlspecialchars = function (string, quote_style, charset, double_encode) {
    var optTemp = 0, i = 0, noquotes = false;
    if (typeof quote_style === 'undefined' || quote_style === null)
      quote_style = 2;
    string = string.toString ();
    if (double_encode !== false)
      string = string.replace (/&/g, '&amp;');
    string = string.replace (/</g, '&lt;').replace (/>/g, '&gt;');
    var OPTS = {
      'ENT_NOQUOTES': 0,
      'ENT_HTML_QUOTE_SINGLE': 1,
      'ENT_HTML_QUOTE_DOUBLE': 2,
      'ENT_COMPAT': 2,
      'ENT_QUOTES': 3,
      'ENT_IGNORE': 4
    };
    if (quote_style === 0)
      noquotes = true;
    if (typeof quote_style !== 'number') {
      quote_style = [].concat (quote_style);
      for (i = 0; i < quote_style.length; i++) {
        if (OPTS[quote_style[i]] === 0)
          noquotes = true;
        else if (OPTS[quote_style[i]])
          optTemp = optTemp | OPTS[quote_style[i]];
      }
      quote_style = optTemp;
    }
    if (quote_style & OPTS.ENT_HTML_QUOTE_SINGLE)
      string = string.replace (/'/g, '&#039;');
    if (!noquotes)
      string = string.replace (/"/g, '&quot;');
    return string;
  }
  
  /**
   * @see http://phpjs.org/functions/urlencode
   */
  window.calculator.urlencode = function (str) {
    str = (str + '').toString ();
    return encodeURIComponent (str).replace (/!/g, '%21').replace (/'/g, '%27').replace (/\(/g, '%28').replace (/\)/g, '%29').replace (/\*/g, '%2A').replace (/%20/g, '+');
  }
  

