/* jshint devel:true */
(function ($, win, doc) {
  'use strict';

  /**
   * CircleLoaderCard
   * @type {Prototype}
   */
  var CircleLoaderCard = function (options) {

    // Set card and options
    this.setopts(options);

    // Autoload the script
    this.init();
  };

  /**
   * Set card
   */
  CircleLoaderCard.prototype.card = null;

  /**
   * Set opts
   */
  CircleLoaderCard.prototype.opts = null;

  /**
   * Set gauge
   */
  CircleLoaderCard.prototype.gauge = null;

  /**
   * Set default options
   * @return {Object} this
   */
  CircleLoaderCard.prototype.setopts = function (options) {

    // Check if param options is empty
    options = options || {};

    // Set sub object for animation options
    var animationOpts = {

      // Set duration of loader's animation
      duration: options && options.duration || 1200,

      // Set type of easing animation
      easing: options && options.easing || 'circleProgressEasing'
    };

    // Setup main options
    var opts = {

      // Set color of circle's background
      bgcolor:  options.bgcolor || '#e1e1e1',

      // Set color of circle's overlay
      ovcolor:  options.ovcolor || '#22cf82',

      // Set size of circle
      size: options.size || 200,

      // Set width of overlay
      lineWidth: options.lineWidth || 17,

      // Set degrees starting point of animation
      rotate: options.rotate || 0,

      // Set total numbers of items present in the card
      numTotal: options.numTotal || 150,

      // Set how many new items are present in the card
      numNew: options.numNew || 110,

      // Set type of easing animation
      animation: animationOpts
    };

    // Assign opts to this object
    this.opts = opts;

    // Set card
    this.setcard(options.card);

    // Calculate gauge
    this.gauge = this.calculatePercent();

    return this;
  };

  /**
   * Get card DOM object
   * @return {Object} this
   */
  CircleLoaderCard.prototype.setcard = function (card) {

    // If card not exist throw an error and block the execution
    if (!card || card.length <= 0) { throw('Need to set the right div#id'); }

    // Obtain jQuery DOM object
    var domcard = $(card);

    // Assign opts to this object
    this.card = domcard;

    // Create elements
    if (this.card) {
      this.createElements();
    }

    return this;
  };

  /**
   * Create elements needs for script
   * @return {Object} this
   */
  CircleLoaderCard.prototype.createElements = function () {

    // Create and set elements canvas, spans and get 2D context
    this.canvas = doc.createElement('canvas');

    // For IE lower than 9
    if (typeof G_vmlCanvasManager !== 'undefined') {
      G_vmlCanvasManager.initElement(this.canvas);
    }

    this.ctx = this.canvas.getContext('2d');
    this.msg = $('<div/>', {'class': 'msg'});
    this.line1 = $('<span/>', {'class': 'line1', style: 'display: none'});
    this.line2 = $('<span/>', {'class': 'line2', style: 'display: none'});
    this.loading = $('<span/>', {'class': 'line2'});

    // Set value of text in span
    this.loading.text('loading');

    // Set Total value
    this.line1.text(this.opts.numNew + ' new');

    // Set New value
    this.line2.text(this.opts.numTotal + ' total');

    return this;
  };

  /**
   * Calculate the gauge
   * @return number value of gauge
   */
  CircleLoaderCard.prototype.calculatePercent = function () {

    // Make the calculation based on options set before
    var gauge = (this.opts.numNew / this.opts.numTotal) * 100;

    return gauge;
  };

  /**
   * Function to draw circles
   * @param  number  size
   * @param  number  lineWidth
   * @param  string  color
   * @param  number  value
   * @param  boolean animated
   */
  CircleLoaderCard.prototype.drawCircle = function(size, line, color, value, anim) {

    // Local this
    var _this = this;

    // Calculate radius
    var radius = size / 2 - line;

    // Divide value making compatible value
    value = value / 100;

    // Func to draw shapes
    function draw (v) {
      _this.ctx.save();
      _this.ctx.translate(size / 2, size / 2); // change center
      _this.ctx.rotate((-1 / 2 + _this.opts.rotate / 180) * Math.PI); // rotate -90 deg
      _this.ctx.beginPath();
      _this.ctx.arc(0, 0, radius, 0, Math.PI * 2 * v);
      _this.ctx.lineCap = 'square';
      _this.ctx.lineWidth = line;
      _this.ctx.strokeStyle = color;
      _this.ctx.stroke();
      _this.ctx.restore();
    }

    // Check if there flag animation is set to true or not
    if (!anim) {

      // Draw in a single step
      draw(value);

    } else {

      // Trigger animation start
      _this.card.trigger('animation-start');

      // Draw in a multiple steps
      $(_this.canvas).css({ progress: 0 }).stop().animate({ progress: value },
        $.extend({}, _this.opts.animation, {

          step: function(p) {

            // Draw this single step
            draw(p);

            // Trigger animation progress
            _this.card.trigger('animation-progress', [p / value, p]);
          },

          complete: function() {

            // Trigger animation end
            _this.card.trigger('animation-end');
          }
        })
      );
    }
  };

  /**
   * Redraw function during resizing
   */
  CircleLoaderCard.prototype.redraw = function (size, line) {

    size = size || this.opts.size;
    line = line || this.opts.lineWidth;

    // Update size
    this.canvas.width = this.canvas.height = size;

    // Draw base circle
    this.drawCircle(size, line, this.opts.bgcolor, 100);

    // Draw overlay circle
    this.drawCircle(size, line, this.opts.ovcolor, this.gauge, true);
  };

  /**
   * Behaviour for bind resize of window
   */
  CircleLoaderCard.prototype.bindResize = function () {

    // Create vars
    var iWidth, uWidth, iHeight, ratioW, fontSize, updatedSize, lineWidth;

    // Initial width
    iWidth = parseInt(this.card.parent().css('max-width'), 10);

    // Updated width
    uWidth = this.card.parent().width();

    // Ratio width
    ratioW = uWidth / iWidth;

    // Initial height
    iHeight = parseInt(this.card.parent().css('max-height'), 10);

    // Updated font-size
    fontSize = uWidth < iWidth ? (uWidth / iWidth * 100) : '100';

    // Update font-size of card
    this.card.parent().css('font-size', fontSize + '%');

    // Update height of card with width ratio
    this.card.parent().css('height', iHeight * ratioW + 'px');

    // Set width/height of canvas
    updatedSize = this.opts.size * ratioW;
    lineWidth = this.opts.lineWidth * ratioW;

    this.card.height(updatedSize);

    // Redraw during resizing
    this.redraw(updatedSize, lineWidth);
  };

  /**
   * Load all events
   */
  CircleLoaderCard.prototype.loadEvents = function () {

    // Local this
    var _this = this;

    // Appends messages
    _this.card.append(_this.msg);
    _this.msg.append(_this.loading).append(_this.line1).append(_this.line2);

    // Append the canvas
    _this.card.append(_this.canvas);

    // Bind the resize of window
    $(win).resize(function(){ _this.bindResize(); }).resize();

    // Event: Simulate loading
    _this.card.on('animation-start', function () {

      // Show loading
      _this.loading.show();

      // Show the rest
      _this.line1.css({'display': 'none'});
      _this.line2.css({'display': 'none'});
    });

    // Event: End animation
    _this.card.on('animation-end', function () {

      // Hide loading
      _this.loading.hide();

      // Show the line1
      _this.line1.css({'display': 'block','opacity': 0,'margin-left': '50%'})
        .animate({'opacity':1,'margin-left':0}, 300);

      // Show the line2
      _this.line2.css({'display': 'block','opacity': 0,'margin-right': '50%'})
        .animate({'opacity':1,'margin-right':0}, 300);
    });

    /**
     * Event: click on close button
     */
    $('#card-close').on('click', function () {
      _this.card.parent().animate({'opacity': 0}, 300, function(){
        _this.card.parent().css({'display':'none'});
      });
      $('#card-open').animate({'opacity': 1}, 300);
    });

    /**
     * Event: click on close button
     */
    $('#card-open').on('click', function () {
      _this.card.parent().css({'display':'block'}).animate({'opacity': 1}, 300);
      $(this).animate({'opacity': 0}, 300);

      // Restart the script
      _this.restart();
    });
  };

  /**
   * Restart animation of card
   */
  CircleLoaderCard.prototype.restart = function () {

    // Trig bind resize function in order to restart the script
    this.bindResize();
  };

  /**
   * Set size of card from external
   */
  CircleLoaderCard.prototype.size = function (size) {

    if (!size) { return; }

    // Set new size
    this.opts.size = size;

    // Restart the script
    this.restart();
  };

  /**
   * Start the script
   */
  CircleLoaderCard.prototype.init = function () {

    var _this = this;

    // Load everything on page ready
    $(doc).ready(function($) {

      // Load events and start the script
      _this.loadEvents();
    });
  };

  /**
   * Return as public object
   */
  window.CircleLoaderCard = CircleLoaderCard;

})(jQuery, this, this.document);

