/*
    This file is part of Accountant.

    Accountant is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Foobar is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Accountant.  If not, see <http://www.gnu.org/licenses/>.
 */
// Util function to show a message in message placeholder.
function message(alertType, title, message) {
  $(".alert").alert('close');
  $("#message-placeholder").append('<div class="alert alert-' + alertType + '"><button type="button" class="close" data-dismiss="alert">&times;</button><h4>' + title + '</h4>' + message + '</div>');
}

var EntryController = function($scope, $http, $rootScope, $filter) {
    // Entry store and selection
    $scope.entries = [];
    $scope.selectedItem = null;

    $scope.account = null;

    // Placeholder for saved value to cancel entry edition
    $scope.savedItem = null;

    $scope.entriesLoaded = function(entries) {
      var entriesReversed = entries.slice().reverse();

      var categories = [];

      var chartValues = [];

      var pieChartValuesTmp = {};
      var pieChartValues = [];

      angular.forEach(entriesReversed, function(entry) {
        var category = entry.category;
        var value = entry.value ? Number(entry.value) : null;
        var sold = entry.sold ? Number(entry.sold) : null;
        var operation_date = entry.operation_date;

        if(operation_date && sold) {
            chartValues.push([entry.operation_date, sold]);
        }

        if(category && category != '') {
          if(categories.indexOf(category) == -1) {
            categories.push(category);
          }

          if(value && value < 0.0) {
            var oldValue = 0.0;

            if(pieChartValuesTmp[category]) {
              oldValue = pieChartValuesTmp[category];
            }

            pieChartValuesTmp[category] = oldValue - value;
          }
        }
      });
 
      // Second pass: transform to an array readable by jqplot.
      angular.forEach(pieChartValuesTmp, function(value, key) {
        pieChartValues.push([key, value]);
      });

      $scope.categories = categories;

      $scope.drawChart({account: $scope.account, entries: chartValues}, "#entries-chart-placeholder");
      $scope.drawPieChart(pieChartValues, "#expense-categories-chart-placeholder");
    };

    // Function to load entries from server for a specific account and month.
    $scope.loadEntries = function(account, month) {
      if(account) {
          $scope.account = account;
      }

      // Clean up selected entry.
      $scope.selectedItem = null;
      $scope.savedItem = null;

      if(account && month) {
        $http.get("api/entries/" + account.id + "/" + month.year + "/" + month.month).success($scope.loadEntries_success);
      } else {
        $scope.loadEntries_success(null);
      }
    };

    // Load entries success callback
    $scope.loadEntries_success = function(data) {
        var entries = [{
          id: null,
          pointed: false,
          operation_date: null,
          label: null,
          value: null,
          sold: null,
          pointedsold: null,
          category: null,
          account_id: null,
          state: 'edit'
        }];

        if(data) {
          entries = entries.concat(angular.fromJson(data));
        }

        $scope.entries = entries;

        $scope.$emit("entriesLoadedEvent", {entries: entries});
    };

    // Returns the CSS class for a pointed entry.
    $scope.pointedEntryClass = function(entry) {
        if(entry.pointed) {
            return "active";
        }
    };

    // Returns the CSS class for an entry row.
    $scope.entryRowClass = function(sold) {
        if(sold < $scope.account.authorized_overdraft) {
            return 'error';
        } else if (sold < 0) {
            return 'warning';
        }
    };

    // Returns the CSS class for an entry sold.
    $scope.entryValueClass = function(sold) {
        if(sold < $scope.account.authorized_overdraft) {
            return 'text-error';
        } else if (sold < 0) {
            return 'text-warning';
        }
    };

    // Starts editing an entry
    $scope.editEntry = function(entry) {
        // Cancel previous editing.
        if($scope.selectedItem) {
            $scope.cancelEditEntry($scope.selectedItem);
        }

        // Save current entry values.
        $scope.savedItem = angular.copy(entry);
        $scope.selectedItem = entry;

        // Enter edit state.
        entry.state='edit';
    };

    // Returns true if the entry is a new one.
    $scope.isNew = function(entry) {
      return !entry.id;
    };

    // Returns true if the entry is in editing state.
    $scope.isEditing = function(entry) {
      return entry.state === 'edit';
    };

    // Returns true if the entry is in displaying state.
    $scope.isDisplaying = function(entry) {
      return entry.id && (!entry.state || entry.state === 'display');
    };

    $scope.iconSaveClass = function(entry) {
      if($scope.isNew(entry)) {
        return "icon-plus";
      } else if ($scope.isEditing(entry)) {
        return "icon-ok";
      }
    };

    $scope.iconCancelClass = function(entry) {
      if($scope.isNew(entry)) {
        return "icon-remove";
      } else if ($scope.isEditing(entry)) {
        return "icon-ban-circle";
      }
    };

    // Cancel current editing entry or clears field if a new one.
    $scope.cancelEditEntry = function(entry) {
      if ($scope.isNew(entry)) {
        // We are cancelling the new entry, just reset it.
        entry.id = null; // id should not change, but just in case...
        entry.pointed = false;
        entry.operation_date = null;
        entry.label = null;
        entry.value = null;
        entry.account_id = $scope.account.id; // account_id should not change, but just in case...
        entry.category = null;
      } else if($scope.isEditing(entry)) {
        if($scope.savedItem) {
          // Reset selected item fields to saved item ones.
          entry.id = $scope.savedItem.id; // id should not change, but just in case...
          entry.pointed = $scope.savedItem.pointed;
          entry.operation_date = $scope.savedItem.operation_date;
          entry.label = $scope.savedItem.label;
          entry.value = $scope.savedItem.value;
          entry.account_id = $scope.savedItem.account_id; // account_id should not change, but just in case...
          entry.category = $scope.savedItem.category;
        }

        // Reset saved and selected items to null.
        $scope.savedItem = null;
        $scope.selectedItem = null;

        // Enter display state.
        entry.state = 'display';
      }
    };

    // Points an entry.
    $scope.pointEntry = function(entry) {
      if(entry.pointed) {
        entry.pointed = false;
      } else {
        entry.pointed = true;
      }

      // Save the entry if not new.
      if(!$scope.isNew(entry)) {
        $scope.saveEntry(entry);
      }
    };

    // Saves an entry.
    $scope.saveEntry = function(entry) {
      // Affects the account ID if not (should never happen)
      if(!entry.account_id) {
          entry.account_id = $scope.account.id;
      }

      // Prepare the Ajax call to save the entry.
      var type;
      var url = "api/entries";

      if(!$scope.isNew(entry)) {
        url += "/" + entry.id;
      }

      // Ajax call to save an entry
      $http.put(url, angular.toJson(entry)).success(function(data) {
        message("success", "Save", data);

        // $scope.savedItem = null;

        // Send the "entry saved" event.
        $scope.$emit("entrySavedEvent", entry);
      });
    };

    // Removes an entry.
    $scope.removeEntry = function(entry, modalScope) {
      // Cancel current editing.
      if (!$scope.isNew(entry)) {
        $http.delete("api/entries/" + entry.id).success(function (result) {
          message("success", "Delete", result);

          // Send the "entry removed" event.
          $scope.$emit("entryRemovedEvent", entry);

          $scope.closeModal(modalScope);
        }).error(function (data) {
          message("error", "Delete", data);

          $scope.closeModal(modalScope);
        });
      }
    };

    $scope.closeModal = function(modalScope) {
      // Close the modal dialog
      if(modalScope && modalScope.dismiss) {
        modalScope.dismiss();
      }
    };

    // Function to draw the sold evolution chart.
    $scope.drawChart = function(data, elementId) {
      // Clear previous chart
      //var element = angular.element(elementId);
      //element.html("");
      //element.css("height", "0px");
    
      var entries = data.entries;
    
      //if(entries && entries.length > 1) {
        // Prepare for today vertical line.
        var today = new Date();
        today.setHours(0);
        today.setMinutes(0);
    
        // Find first and last days to set limits of the x axis.
        var day = 24 * 60 * 60 * 1000;
        var firstDate = $filter('date')(new Date(Date.parse(entries[0][0]).valueOf() - day), 'yyyy-MM-dd');
        var lastDate = $filter('date')(new Date(Date.parse(entries[entries.length -1][0]).valueOf() + day), 'yyyy-MM-dd');
        //var firstDate = new Date(Date.parse(entries[0][0]).valueOf() - day);
        //var lastDate = new Date(Date.parse(entries[entries.length -1][0]).valueOf() + day);
    
        // Plot chart, and store it in a window parameter for resize callback (need to be done better than it...)
        var chart = nv.models.lineChart()
          .x(function(d) { return d3.time.format("%Y-%m-%d").parse(d[0]); })
          .y(function(d) { return new Number(d[1]); });
        
        chart.lines.interpolate("monotone"); 

        chart.xAxis.axisLabel("Date").tickFormat(function(d) {
          return d3.time.format("%Y-%m-%d")(new Date(d));
        });
        chart.xAxis.scale().range([firstDate, lastDate]);

        chart.yAxis.axisLabel("Solde").tickFormat(d3.format('.02f'));

        // FIXME add vertical line for today
        graph = d3.select(elementId + " svg").datum([
          { color: "orange", key: "Zero", values:[
            [firstDate, "0"],
            [lastDate, "0"]
          ]},
          { color: "red", key: "Authorized overdraft", values : [
            [firstDate, new Number($scope.account.authorized_overdraft)],
            [lastDate, new Number($scope.account.authorized_overdraft)]
          ]},
          { color: "darkblue", key: "Sold evolution", values: entries},
        ]).transition().duration(1200).call(chart);

        nv.utils.windowResize(chart.update);
    };

    // Function to draw the expense category pie chart.
    $scope.drawPieChart = function(entries, elementId) {
      //if(entries && entries.length > 1) {
        var chart = nv.models.pieChart()
          .x(function(d) { return d[0]; })
          .y(function(d) { return d[1]; })
          .showLabels(true);

        d3.select(elementId + " svg").datum([{key: "Expenses", values: entries}]).transition().duration(1200).call(chart);

        nv.utils.windowResize(chart.update);
      //}
    };

    $rootScope.$on("monthsLoadedEvent", function(event, args){
        $scope.loadEntries(args.account, args.month);
    });

    $scope.$on("entriesLoadedEvent", function(event, args) {
        $scope.entriesLoaded(args.entries);
    });
};

// Default AJAX error handler.
//$(document).ajaxError(function(event, xhr, settings) {
//  message("error", xhr.statusText, xhr.responseText);
//});

