//= jquery
//= console-helper
//= jquery.gridster.with-extras
//= underscore

$(function() {


  $('.easy-modal').easyModal({
    top: 200,
    overlay: 0.2
  });

  function resizeBaseLineBasedOnWidgetWith ($el){
    var RATIO = 0.035; // ratio width vs font-size. i.e: for a 400 width widget, 400 * 0.035 = 14px font size as baseline
    var divWidth = $el.width();
    var newFontSize = divWidth * RATIO;
    $('.content.auto-font-resize', $el).css({"font-size" : newFontSize + 'px'});
  }

  //----------------------
  // Alert for timeouts
  //----------------------
  function check_last_server_communication (li, config){
    
    config = $.extend({}, config);
    
    var lastUpdate = $(li).attr('last-update');

    if (lastUpdate){
      var elapsedEl = '.widget-title span.widget-elapsed';
      if ($(elapsedEl, li).length === 0){
        $('.widget-title', li).append('<span class="widget-elapsed"></span>');
      }

      var elapsed = ((+new Date()) - lastUpdate);

      if (config.interval){ // job has a specific predefined interval
        // calculate based on retryOnErrorTimes or use 2xinterval.
        var max_time_to_show_offline = config.interval * (config.retryOnErrorTimes || 2);
        if (elapsed > max_time_to_show_offline){ // this widget if offline
          var str_elapsed = ' <span class="alert alert_high">&gt;1h</span>';
          $('.widget-title span.widget-elapsed', li).html(str_elapsed);
          $(li).addClass('offline');
        }
        else{
          $('.widget-title span.widget-elapsed', li).html('');
          $(li).removeClass('offline');
        }

        $('.widget-title span.widget-elapsed', li).html('');
      }
    }
  }

  var defaultHandlers = { // they can be overwritten by widget´s custom implementation
    onError : function (el, data){
      console.error(data);
    },
    onInit : function (el, data){
      $(el).parent().children().hide();
      $(el).parent().children(".spinner").show();
      resizeBaseLineBasedOnWidgetWith($(el));
    }
  };

  var widgetMethods = { // common methods that all widgets implement
    log : function (data){
      socket_log.emit('log', {widgetId : this.eventId, data : data}); // emit to logger
    },
    configure: function() {

    }
  };

  var globalHandlers = { // global pre-post event handlers
    onPreError : function (el, data){
      $(el).children().hide();
      $(el).children(".error").show();
    },

    onPreData : function (el, data){
      $(el).children().hide();
      $(el).children(".widget-container").show();
    }
  };

  if (!$("#widgets-container").length)
      return;

  function log_error (widget, err){
    var errMsg = 'ERROR on ' + widget.eventId + ': ' + err;
    console.error(errMsg);
    socket_log.emit('log', {widgetId : widget.eventId, error : errMsg}); // emit to logger
  }

  function bind_widget(io, li){
    var widgetId = encodeURIComponent($(li).attr("data-widget-id"));
    var eventId = $(li).attr("data-event-id");

    var $errorContainer = $("<div>").addClass("error").addClass("icon-message").appendTo($(li)).hide();
    $errorContainer.append($("<div>").addClass("container").append($("<img src=\"images/warning.png\">")));

    var $spinnerContainer = $("<div>").addClass("spinner").addClass("icon-message").appendTo($(li)).hide();
    var spinner = new Spinner({className: 'spinner', color:'#fff', width:5, length:15, radius: 25, lines: 12,  speed:0.7}).spin();
    $spinnerContainer.append($("<div>").addClass("container").append(spinner.el));

    $spinnerContainer.prepend('<span style="float:right" class="configure" title="Configure the widget"></span>');

    $spinnerContainer.children('.configure').click(function(){
      configureWidget(widgetId,li);
    });

    var $widgetContainer = $("<div>").addClass("widget-container").appendTo($(li)).hide();

    // fetch widget html and css
    $widgetContainer.load("/widgets/" + widgetId, function() {

      // fetch widget js
      $.get('/widgets/' + widgetId + '/js', function(js) {

        var widget_js;
        try{
          eval('widget_js = ' + js);
          widget_js.eventId = eventId;
          widget_js = $.extend({}, defaultHandlers, widget_js);
          widget_js = $.extend({}, widgetMethods, widget_js);
          widget_js.onInit($widgetContainer[0]);
        }
        catch (e){
          log_error(widget_js, e);
        }

        io.on(eventId, function (data) { //bind socket.io event listener

          if (data.error){
            globalHandlers.onPreError.apply(widget_js, [$(li), data]);
          } else {
            globalHandlers.onPreData.apply(widget_js, [$(li)]);
          }

          var f = data.error ? widget_js.onError : widget_js.onData;
          var $container = data.error ? $errorContainer : $widgetContainer;

          try{
            f.apply(widget_js, [$container, data]);

          }
          catch (e){
            log_error(widget_js, e);
          }

           
          $container.css("background-color","rgb(54, 54, 54)");

          setTimeout(function(){
              $container.css("background-color","#0f0f0f");
          },200);

          // save timestamp
          $(li).attr("last-update", +new Date());
          $(li).append('<span class="gs-resize-handle gs-resize-handle-both"></span>');
          $(li).prepend('<span style="float:right" class="configure" title="Configure the widget"></span>');

          $(li).children('.configure').click(function(){
            configureWidget(widgetId,li);
          });


          //----------------------
          // Server timeout notifications
          //----------------------
          if (!data.error && !widget_js.config){ // fill config when first data arrives
            widget_js.config = data.config;
            setInterval(function(){
              check_last_server_communication(li, widget_js.config);
            }, 5000);
          }
        });

        io.emit("resend", eventId);
        console.log("Sending resend for " + eventId);

      });
    });
  }


    function renderForm($el,config) {

          for(name in config) {
            var field =  config[name];
            $el.append("<div style='color:white;margin-bottom:20px'>" + name + ": " + createField(name,field) +"<div class='field-help'>"+field.help+"</div></div>");
          };


    };


  function createField(name, field) {
    var value = field.value ? field.value : (field.defaultValue ?  field.defaultValue : '');
    return '<input type="'+getType(field)+'" style="width:100%" name="'+name+'" value="'+value+'"></input>';
  }

    function getType(field){
        if(field.type == "int") {
          return "number";
        } else  if(field.type == "password") {
          return "password"
        }

        return "input";
    }

  function configureWidget(widgetId,li) {
      $('.easy-modal').empty();

      $.get(getDashboard()+ '/widgets/' + widgetId + '/config', function(config) {

           $("<input class='button button-danger button-small pull-right' type='button' value='Remove'/>").click(function() {deleteWidget(widgetId,li) }).appendTo('.easy-modal');

           $('.easy-modal').append("<h2 class='configuration-modal-title'>"+widgetId+"</h2>");

          var form = $("<form method='POST' action='/"+getDashboard()+"/widgets/add'>").appendTo('.easy-modal');

          renderForm(form,config);

           $("<input class='button' type='button' value='Save'/>").click(function() {saveWidgetConfig(widgetId,li) }).appendTo('.easy-modal');

           $('.easy-modal').trigger('openModal');
      });
  }

  function deleteWidget(widgetId,li) {
    // Remove by position ?  $(li).data('row'), $(li).data('col'))
    $.ajax({
        dataType : "json",
        url: getDashboard()+ '/widgets/' + widgetId,
        type: "DELETE",
    }).always(function() {
            $('.easy-modal').trigger('closeModal');
            $(li).remove();
    });
  }

  function saveWidgetConfig(widgetId,li) {
    var config= {};
    $('.easy-modal').find('input').each(function() {
      if(this.name) {
        if(isNumber(this.value)) {
          config[this.name] = parseInt(this.value);
        }else {
          config[this.name] = this.value;
        }

      }
    });

    $.ajax({
        dataType : "json",
        url: getDashboard()+ '/widgets/' + widgetId + '/config',
        data: JSON.stringify(config),
        type: "POST",
        contentType:"application/json; charset=utf-8"
    }).always(function() {
            $('.easy-modal').trigger('closeModal');
    });

  }

  function isNumber(str) {
     var pattern = /^\d+$/;
     return pattern.test(str);  // returns a boolean
  }



  function getDashboard() {
    var part = document.URL.split('/');
    return part[part.length-1];
  }

  function buildUI(mainContainer, gridsterContainer){
    var gutter = parseInt(mainContainer.css("paddingTop"), 10) * 2;
    var gridsterGutter = gutter/2;
    var height = 1080 - mainContainer.offset().top - gridsterGutter;
    var width = mainContainer.width();
    var vertical_cells = grid_rows, horizontal_cells = grid_columns;
    var widgetSize = {
      w: (width - horizontal_cells * gutter) / horizontal_cells,
      h: (height - vertical_cells * gutter) / vertical_cells
    };

    var gridster = gridsterContainer.gridster({
      min_cols:6,
      min_rows:4,
      widget_margins: [gridsterGutter, gridsterGutter],
      widget_base_dimensions: [widgetSize.w, widgetSize.h],
      draggable:{
        stop: function(){
            saveLayout(this.serialize());
        }
      },
       resize: {
            enabled: true,
            stop: function(e, ui, $widget) {
              saveLayout(this.serialize());
            },
          }
    }).data('gridster');

    gridster.add_widget.apply(gridster, ['<li class="add-widget"></li>', 1, 1]);


      $('li.add-widget').click(function(){
        showWidgetList(this);
      });




    function showWidgetList(el) {

      $('.easy-modal').empty();

          $.get(getDashboard()+ '/widgets/', function(widgets) {

              $('.easy-modal').append("<h2 class='configuration-modal-title'>Add Widget</h2>");
              var modalBody = $("<div class='new-widget-modal-body'/>").appendTo('.easy-modal');

              if(Object.keys(widgets).length ==0) {
                modalBody.append("<h3 class='configuration-modal-title'>No more widgets are available.</h3>");
              }

              for(name in widgets) {
                var widget = widgets[name];

                var container = $("<div class='new-widget-container' />");
                container.append("<div class='new-widget-image'><img src='/images/widgets/"+name+".png'></div>");
                
                var content = $("<div class='new-widget-content'/>").appendTo(container);
                content.append("<h3 class='new-widget-title'>"+ widget.title +"</h3>");
                content.append("<p class='new-widget-description'>"+ widget.description +"</p>");
                container.appendTo(modalBody);

                container.click(function() {
                    $('.easy-modal').empty();
                    $('.easy-modal').append("<h2 class='configuration-modal-title'>Add Widget: "+  widget.title +"</h2>");

                    var $form = $("<form method='POST' action='/"+getDashboard()+"/widgets/add'>").appendTo('.easy-modal');

                     $form.append("<input type='hidden' name='widget' value='"+name+"'/>");
                     $form.append("<input type='hidden' name='job' value='"+widget.job +"'/>");

                    renderForm($form,widget.config);


                    $("<input class='button' type='submit' value='Add'/>").click(function() {addWidget() }).appendTo($form);

                })
              };

               $('.easy-modal').trigger('openModal');
          });
    }




    function saveLayout(layout) {
        $.ajax
        ({
            type: "POST",
            url: getDashboard()+ '/layout',
            contentType : 'application/json',
            data: JSON.stringify(layout),
            success: function () {

            }
        })
    }


    // Handle browser resize
    var initialWidth = mainContainer.outerWidth();
    var initialHeight = mainContainer.outerHeight();

    $(window).resize(function() {
        var scaleFactorWidth = $(window).width() / initialWidth;
        var scaleFactorHeight = $(window).height() / initialHeight;
        mainContainer.css("transform", "scale(" + Math.min(scaleFactorWidth, scaleFactorHeight) + ")");
    }).resize();

  }

  function bindSocket (io, gridsterContainer){
    gridsterContainer.children("li:not(.add-widget)").each(function(index, li) {
      $(li).empty();
      bind_widget(io, li);
    });
  }

  //----------------------
  // Main
  //----------------------

  // disable caching for now as chrome somehow screws things up sometimes
  $.ajaxSetup({cache: false});

  var mainContainer = $("#main-container");
  var gridsterContainer = $(".gridster ul");

  buildUI(mainContainer, gridsterContainer);

  var options = {
    'reconnect': true,
    'reconnection delay': 1000,
    'reopen delay': 3000,
    'max reconnection attempts': Infinity,
    'reconnection limit': 60000
  };

  //----------------------
  // widget socket
  //----------------------
  var socket_w = io.connect('/widgets', options);

  socket_w.on("connect", function() {

    console.log('connected');
    $('#main-container').removeClass("disconnected");

    bindSocket(socket_w, gridsterContainer);

    socket_w.on("disconnect", function() {
      $('#main-container').addClass("disconnected");
      console.log('disconnected');
    });

    // reconnect
    socket_w.on('reconnecting', function () {
      console.log('reconnecting...');
    });

    socket_w.on('reconnect_failed', function () {
      console.log('reconnected FAILED');
    });

  });

  //----------------------
  // log socket
  //----------------------
  var socket_log = io.connect('/log', options);
  socket_log.on("connect", function() {
    console.log('log socket connected');
  });

  //----------------------
  // status socket
  //----------------------
  var socket_s = io.connect('/', options);
  var serverInfo;
  socket_s.on("serverinfo", function(newServerInfo) {
    if (!serverInfo) {
      serverInfo = newServerInfo;
    } else if (newServerInfo.startTime > serverInfo.startTime) {
      window.location.reload();
    }
  });
});

var Widgets = {}; //support legacy widgets
