text: /* loader.js */
  /* global ysy */
  window.ysy = window.ysy || {};
  ysy.data = ysy.data || {};
  ysy.data.loader = ysy.data.loader || {};
  $.extend(ysy.data.loader, {
    /*
     * this object is responsible for downloading and preparing data from server
     */
    _name: "Loader",
    loaded: false,
    inited: false,
    issueIdListMap: {},
    _onChange: [],
    init: function () {
      var settings = ysy.settings;
      var data = ysy.data;
      if (settings.paths.rootPath.substr(-1) !== "/") {
        settings.paths.rootPath += "/";
      }
      if (!settings.project) {
        settings.global = true;
      }
      if (settings.project) {
        settings.projectID = parseInt(settings.project.id);
      }
      settings.zoom = new ysy.data.Data();
      settings.zoom.init({zoom: data.storage.getSavedZoom() || ysy.settings.defaultZoom || "day", _name: "Zoom"});
      settings.controls = new ysy.data.Data();
      settings.controls.init({controls: true, _name: "Task controls"});
      settings.baseline = new ysy.data.Data();
      settings.baseline.init({open: false, _name: "Baselines"});
      settings.critical = new ysy.data.Data();
      settings.critical.init({open: false, active: false, _name: "Critical path"});
      settings.addTask = new ysy.data.Data();
      settings.addTask.init({open: false, type: "issue", _name: "Add Task"});
      settings.resource = new ysy.data.Data();
      settings.resource.init({open: false, _name: "Resource Management"});
      settings.scheme = new ysy.data.Data();
      settings.scheme.init({by: ysy.settings.schemeBy, _name: "Schema switch"});
      settings.sumRow = new ysy.data.Data();
      settings.sumRow.init({_name: "SumRow"});
      settings.sample = new data.Data();
      data.limits = new data.Data();
      data.limits.init({_name: "Limits", openings: {}});
      data.relations = new data.Array().init({_name: "RelationArray"});
      data.issues = new data.Array().init({_name: "IssueArray"});
      data.milestones = new data.Array().init({_name: "MilestoneArray"});
      data.projects = new data.Array().init({_name: "ProjectArray"});
      data.baselines = new data.Array().init({_name: "BaselineArray"});
      ysy.view.patch();
      ysy.proManager.patch();
      settings.sample.init();
      this.inited = true;
    },
    load: function () {
      // second part of program initialization
      this.loaded = false;
      //this.projects=new ysy.data.Array;
      //var data=ysy.availableProjects;
      ysy.log.debug("load()", "load");
      if (ysy.settings.sample.active) {
        ysy.pro.sample.loadSample(ysy.settings.sample.active);
      } else {
        ysy.gateway.loadGanttdata(
            $.proxy(this._handleMainGantt, this),
            function () {
              ysy.log.error("Error: Unable to load data");
            }
        );
      }
    },
    loadSubEntity: function (type, id) {
      if (type === "project") {
        return this.loadProject(id);
      }
    },
    register: function (func, ctx) {
      this._onChange.push({func: func, ctx: ctx});
    },
    /**
     *
     * @param {Array.<{id:int}>} array
     * @param {Array.<int>} oldIds
     * @return {Array.<{id:int}>}
     */
    reorderArray: function (array, oldIds) {
      var newArray = [];
      var arrayPointer = 0;
      for (var i = 0; i < array.length; i++) {
        if (oldIds.length === i || oldIds[i] !== array[i].id) {
          if (i > 0) {
            newArray = array.slice(0, i);
            arrayPointer = i;
            oldIds = oldIds.slice(i);
          }
          break;
        }
      }
      var banned = [];
      for (i = 0; i < oldIds.length; i++) {
        for (var j = arrayPointer; j < array.length; j++) {
          if (array[j].id === oldIds[i]) {
            newArray.push(array[j]);
            banned.push(array[j]);
            break;
          }
        }
      }
      for (i = arrayPointer; i < array.length; i++) {
        if (banned.indexOf(array[i]) > -1) continue;
        newArray.push(array[i]);
      }
      return newArray;
    },
    _fireChanges: function (who, reason) {
      for (var i = 0; i < this._onChange.length; i++) {
        var ctx = this._onChange[i].ctx;
        if (!ctx || ctx.deleted) {
          this._onChange.splice(i, 1);
          continue;
        }
        //this.onChangeNew[i].func();
        ysy.log.log("-- changes to " + (ctx.name ? ctx.name : ctx._name) + " widget");
        $.proxy(this._onChange[i].func, ctx)();
      }
    },
    _handleMainGantt: function (data) {
      if (!data.easy_gantt_data) return;
      var json = data.easy_gantt_data;
      ysy.log.debug("_handleGantt()", "load");
      //  -- LIMITS --
      //ysy.data.limits.set({ // TODO
      //  start_date: moment(json.start_date, "YYYY-MM-DD"),
      //  end_date: moment(json.end_date, "YYYY-MM-DD")
      //});
      //  -- COLUMNS --
      ysy.data.columns = json.columns;
      // ARRAY INITIALIZATION
      //  -- RELATIONS --
      ysy.data.relations.clear();
      //  -- ISSUES --
      ysy.data.issues.clear();
      //  -- MILESTONES --
      ysy.data.milestones.clear();
      //  -- PROJECTS --
      ysy.data.projects.clear();
      // ARRAY FILLING
      //  -- PROJECTS --
      this._loadProjects(json.projects);
      //  -- ISSUES --
      this._loadIssues(json.issues, "root");
      //  -- MILESTONES --
      this._loadMilestones(json.versions); // after issue loading because of shared milestones
      //  -- RELATIONS --
      this._loadRelations(json.relations);
      this._loadHolidays(json.holidays);
      //  -- SCHEMES --
      if (this._loadSchemes) this._loadSchemes(json.schemes);
  
      ysy.log.debug("data loaded", "load");
      ysy.log.message("JSON loaded");
      this._fireChanges();
      ysy.history.clear();
      this.loaded = true;
    },
    _loadIssues: function (json, rootId) {
      if (!json) return;
      if (rootId) {
        if (this.issueIdListMap[rootId]) {
          json = ysy.data.loader.reorderArray(json, this.issueIdListMap[rootId]);
        }
        this.issueIdListMap[rootId] = json.map(function (item) {
          return item.id;
        });
      }
      var issues = ysy.data.issues;
      for (var i = 0; i < json.length; i++) {
        var issue = new ysy.data.Issue();
        issue.init(json[i]);
        issues.pushSilent(issue);
      }
      issues._fireChanges(this, "load");
    },
    _loadRelations: function (json) {
      if (!json) return;
      var relations = ysy.data.relations;
      var allowedTypes = {
        precedes: true,
        finish_to_finish: true,
        start_to_start: true,
        start_to_finish: true
      };
      for (var i = 0; i < json.length; i++) {
        // TODO enable other relation types
        if (allowedTypes[json[i].type]) {
          var rela = new ysy.data.Relation();
        } else {
          rela = new ysy.data.SimpleRelation();
        }
        rela.init(json[i]);
        relations.pushSilent(rela);
      }
      relations._fireChanges(this, "load");
    },
    _loadMilestones: function (json) {
      if (!json) return;
      var milestones = ysy.data.milestones;
      for (var i = 0; i < json.length; i++) {
        var mile = new ysy.data.Milestone();
        mile.init(json[i]);
        milestones.pushSilent(mile);
  
        var issues = mile.getIssues();
        var projectIds = {};
        for (var j = 0; j < issues.length; j++) {
          projectIds[issues[j].project_id] = true;
        }
        delete projectIds[mile.project_id];
        var sharedForIds = Object.getOwnPropertyNames(projectIds);
        if (sharedForIds.length === 0) continue;
        var realProjectId = json[i].project_id;
        delete json[i].project_id;
        for (j = 0; j < sharedForIds.length; j++) {
          var sharedMile = new ysy.data.SharedMilestone();
          $.extend(sharedMile, {
            project_id: parseInt(sharedForIds[j]),
            real_project_id: realProjectId,
            real_milestone: milestones.getByID(mile.id)
          });
          sharedMile.init(json[i]);
          milestones.pushSilent(sharedMile);
        }
      }
      milestones._fireChanges(this, "load");
    },
    _loadProjects: function (json) {
      if (!json) return;
      var projects = ysy.data.projects;
      //var main_id = ysy.settings.projectID;
      for (var i = 0; i < json.length; i++) {
        //if (json[i].id === main_id) continue;
        var project = new ysy.data.Project();
        project.init(json[i]);
        projects.pushSilent(project);
      }
      projects._fireChanges(this, "load");
      var openings = ysy.data.limits.openings;
      for (var id in openings) {
        if (!openings.hasOwnProperty(id)) continue;
        if (ysy.main.startsWith(id, "p")) {
          var realId = id.substring(1);
          project = projects.getByID(realId);
          if (!project) continue;
          if (!project.needLoad) continue;
          project.needLoad = false;
          this.loadProject(realId);
        } else if (this.openIssuesOfProject && ysy.main.startsWith(id, "s")) {
          realId = id.substring(1);
          if (!openings["p" + realId]) continue;
          this.openIssuesOfProject(realId);
        }
      }
    },
    _loadHolidays: function (json) {
      if (!json) return;
      ysy.settings.holidays = json;
      ysy.view.initNonworkingDays();
    },
    loadProject: function () {
    }
  
  });
  if (!ysy.gateway) ysy.gateway = {};
  $.extend(ysy.gateway, {
    loadGanttdata: function (callback, fail) {
      $.getJSON(ysy.settings.paths.mainGantt)
          .done(callback)
          .fail(fail);
    }
  });
  