
(function($) {
  /**
   * Calculator core methods & properties
   */
  $.calc = {
    // Default options
    defaults: {
      'currency': 'Руб.'
    },

    /**
     * Checking pressed key
     *
     * @param event e    Event object
     * @return boolean
     */
    isRightKey: function(e) {
      if (
        (e.which > 47 && e.which < 58) ||               // 0 - 9
        (e.which > 95 && e.which < 106) ||              // 0 - 9 numpad
        (e.which > 36 && e.which < 41) ||               // "left", "up", "right", "down"
        e.which == 9 || e.which == 8 || e.which == 46   // "tab", "backspace", "delete"
      ) {
        return true;
      }
      return false;
    }
  };

  /**
   * Credit calculator
   */
  var credit_calc = {
    credit: {
      // Some properties
      error_header: '<span>Ошибка инициализации кредитного калькулятора!</span><br/>',
      periods: [6, 12, 18],
      opts: null,
      elem: null,

      /**
       * Initializing method
       *
       * @param jQuery elem       Element
       * @param object options    User options
       */
      get: function(elem, options) {
        this.elem = elem;
        var self = this;

        // Checking elements availability
        if (this.checkElements()) {
          return;
        }

        // Initializing options
        this.opts = $.extend({}, $.calc.defaults, options);

        // Adding currency name to the elements
        $('span#currency', this.elem).each(function(){$(this).text(' ' + self.opts.currency);});

        // Binding keyboard events to elements
        $('input#price', this.elem)
        .bind('keydown', function(e) {
          return $.calc.isRightKey(e);
        })
        .bind('keyup', function(e) {
          if ($.calc.isRightKey(e)) {
            self.calc(true);
          }
        });

        $('input#start_fee', this.elem)
        .bind('keydown', function(e) {
          return $.calc.isRightKey(e);
        })
        .bind('keyup', function(e) {
          if ($.calc.isRightKey(e) && self.isRightStartFee()) {
            self.calc();
          }
        });

        // Binding 'click' event to 'period' elements
        $('div#period' + this.periods.join(',div#period'), this.elem).click(function() {
          if (!$(this).hasClass('r_on')) {
            $('div#period' + self.periods.join(',div#period'), self.elem)
            .removeClass('r_on')
            .filter(this)
            .addClass('r_on');
          }

          if (self.isRightStartFee()) {
            self.calc();
          }
        });
      },

      /**
       * Checking elements availability
       *
       * @return integer    Number of errors
       */
      checkElements: function() {
        var errors = [], is_error = 0, self = this;

        if ($('input#price', this.elem).length != 1) {
          is_error++;
          errors.push('Поле "Стоимость услуги" отсутствует или таких элементов более одного.');
        }

        if ($('input#start_fee', this.elem).length != 1) {
          is_error++;
          errors.push('Поле "Первоначальный взнос в кассу" отсутствует или таких элементов более одного.');
        }

        if ($('table.tbl td#credit', this.elem).length != 1) {
          is_error++;
          errors.push('Поле "Сумма кредита" отсутствует или таких элементов более одного.');
        }

        /**
         * Checking length of the each period element
         *
         * @return boolean
         */
        function checkPeriods() {
          for (var p = 0; p < self.periods.length; p++) {
            if ($('div#period' + self.periods[p], self.elem).length != 1) {
              return false;
            }
          }
          return true;
        }

        if (!checkPeriods()) {
          is_error++;
          errors.push('У поля "Срок кредита" должно быть только по одному элементу каждого значения.');
        }

        if ($('table.tbl td#result', this.elem).length != 1) {
          is_error++;
          errors.push('Поле "Ежемесячные выплаты" отсутствует или таких элементов более одного.');
        }

        if (errors.length > 0) {
          $(this.elem).after(
            $("<div/>")
            .attr('id', 'calc_error')
            .html(this.error_header + errors.join('<br/>'))
          );
        }

        return is_error;
      },

      /**
       * Checking start fee value
       *
       * @return boolean
       */
      isRightStartFee: function() {
        var price = parseInt($('input#price', this.elem).val(), 10);
        if (isNaN(price)) { return false; }
        var start_fee = parseFloat($('input#start_fee', this.elem).val());
        if (isNaN(start_fee)) { start_fee = 0; }
        if (start_fee < price / 10) {
          this.showMessage('Сумма первоначального взноса должна быть не менее 10%!');
          $('table.tbl td#credit, table.tbl td#result', this.elem).text('');
          return false;
        }
        else if (start_fee >= price) {
          this.showMessage('Первоначальный взнос не может быть равен или превышать стоимость услуги!');
          $('table.tbl td#credit, table.tbl td#result', this.elem).text('');
          return false;
        }
        return true;
      },

      /**
       * Showing an error box
       */
      showMessage: function(text) {
        $('table.tbl td#message', this.elem).css('padding-bottom', '10px').text(text);
      },

      /**
       * Hiding an error box
       */
      hideMessage: function() {
        $('table.tbl td#message', this.elem).css('padding-bottom', '0').text('');
      },

      /**
       * Main calculation method
       *
       * @param boolean calc_start_fee    If set true when using automatic calculation of start_fee value
       */
      calc: function(calc_start_fee) {
        // годовая процентная ставка
        var year_interest_rate = 15;
        // процентная ставка в долях за месяц
        var month_interest_rate = year_interest_rate / (100 * 12);
        // стоимость услуги
        var price = parseInt($('input#price', this.elem).val(), 10);
        // Resetting all values then price is empty or not a number
        if (isNaN(price)) {
          $('input#start_fee', this.elem).val('');
          $('input#start_fee,table.tbl td#credit,table.tbl td#result', this.elem).text('');
          this.hideMessage();
          return;
        }
        // срок кредита
        var period = parseInt(
          $('div#period' + this.periods.join('.r_on,div#period') + '.r_on', this.elem)
          .attr('id')
          .replace('period', '')
        );
        // первоначальный взнос
        var start_fee = 0;
        // Automatic calculation of start_fee value
        if (calc_start_fee == true) {
          start_fee = price / 10;
          $('input#start_fee', this.elem).val(start_fee);
        }
        else {
          start_fee = parseInt($('input#start_fee', this.elem).val(), 10);
        }
        // сумма кредита
        var credit = price - start_fee;
        // расчет
        var month_fee = ((credit * month_interest_rate) / (1 - Math.pow(1 + month_interest_rate, -period))) + (credit / 100);
        $('table.tbl td#credit', this.elem).text(credit);
        $('table.tbl td#result', this.elem).text(month_fee.toFixed(2) + ' ' + this.opts.currency);
        this.hideMessage();
      }
    }
  };

  /**
   * Installment calculator
   */
  var installment_calc = {
    installment: {
      error_header: '<span>Ошибка инициализации калькулятора в рассрочку!</span><br/>',
      opts: null,
      elem: null,

      get: function(elem, options) {
        this.elem = elem;
        var self = this;

        if (self.checkElements()) {
          return;
        }

        self.opts = $.extend({}, $.calc.defaults, options);

        $('span#currency', this.elem).each(function(){$(this).text(' ' + self.opts.currency);});

        if (typeof $.fn.customStyle == 'function') {
          $('select#start_fee').customStyle();
        }

        $('input#price', this.elem)
        .bind('keydown', function(e) {
          return $.calc.isRightKey(e);
        })
        .bind('keyup', function(e) {
          if ($.calc.isRightKey(e)) {
            self.calc();
          }
        });

        $('select#start_fee', this.elem)
        .bind('change', function() {
          self.calc();
        });
      },

      checkElements: function() {
        var errors = [], is_error = 0;

        if ($('input#price', this.elem).length != 1) {
          is_error++;
          errors.push('Поле "Стоимость услуги" отсутствует или таких элементов более одного.');
        }

        if ($('select#start_fee', this.elem).length != 1) {
          is_error++;
          errors.push('Поле "Первоначальный взнос в кассу" отсутствует или таких элементов более одного.');
        }

        if ($('table.tbl td#result', this.elem).length != 1) {
          is_error++;
          errors.push('Поле "Ежемесячные выплаты" отсутствует или таких элементов более одного.');
        }

        if (errors.length > 0) {
          $(this.elem).after(
            $("<div/>")
            .attr('id', 'calc_error')
            .html(this.error_header + errors.join('<br/>'))
          );
        }

        return is_error;
      },

      calc: function() {
        // срок кредита
        var period = 4;
        // скидка
        var discount = {0: 4.86, 10: 4.39, 20: 3.92, 30: 3.45, 40: 2.97, 50: 2.49};
        // первоначальный взнос в процентах от стоимости услуги
        var start_fee = parseInt($('select#start_fee option:selected', this.elem).val(), 10);
        // стоимость услуги
        var price = parseInt($('input#price', this.elem).val(), 10);
        if (isNaN(price)) {
          $('table.tbl td#result', this.elem).text('');
          return;
        }
        // стоимость услуги со скидкой
        var discounted_price = price - (price / 100) * discount[start_fee];
        // сумма первоначального взноса
        var start_fee_sum = (discounted_price / 100) * start_fee;
        // расчет
        var month_fee = (price - start_fee_sum) / period;
        $('table.tbl td#result', this.elem).text(month_fee.toFixed(2) + ' ' + this.opts.currency);
      }
    }
  };

  $.extend($.calc, credit_calc, installment_calc);

  $.fn.credit_calc = function(options) {
    return $.calc.credit.get(this[0], options);
  };

  $.fn.installment_calc = function(options) {
    return $.calc.installment.get(this[0], options);
  };
})(jQuery);

