if(!kronos)
  kronos = {}

YUI.add('group-controller', function(Y) {

/**
 * Map of the css filters to letters.
 */
var FILTERS = {
  'filter-foto' : 'F',
  'filter-design' : 'D',
  'filter-logo' : 'L',
  'filter-web' : 'W',
  'filter-publikace' : 'P'
};

var ROW_EXPANDED_H = 340;
var ROW_SHRUNK_H   = 50;
var IMG_SHRUNK_H   = 85;
  
var GroupController = function(config) {
  this._groups = { };
  this._groupNames = [];
  
  for(var grpConfigName in config.groups) {
    var grpConfig = config.groups[grpConfigName];
    var grp = new kronos.Group(grpConfig);
    this._groups[grp.name] = grp;
    this._groupNames.push(grpConfig.name);
  }
}

/**
 * Initializes the group controller object. Searches DOM tree for groups.
 * It specially initializes events on the groups and on the group items.
 */
GroupController.prototype.initialize = function() {
  for(var i = 0; i < this._groupNames.length; ++i) {
    var name = this._groupNames[i];
    var grp = this._groups[name];
    this.initializeGroup(grp);
  }
  
  this.hookMenuItems();
}

GroupController.prototype.initializeGroup = function(group) {
  var that = this;
  
  group.state = kronos.GROUP_SHRUNK;
  
  // Create row for the group
  var rowId = 'row-' + group.name;
  var row = new kronos.Row( { name : group.name, controller : that, id : rowId, group : group } );
  row.endAnimationListener = this.endAnimationHandler;
  group.row = row;
  
  // Create scroller for the group
  var scrollerId = 'scroller-' + group.name;
  var scroller = new kronos.Scroller( { name : group.name, controller : that, id : scrollerId, group : group } );
  scroller.mouseOverListener = this.mouseOverListener;
  scroller.mouseOutListener = this.mouseOutListener;
  group.scroller = scroller;
  
  // Create group items
  var cfg = group.config;
  for(var imgName in cfg.images) {
    var img = cfg.images[imgName];
    var item = new kronos.GroupItem(img);
    group.items.push(item);
  }
  
  // If at least one item in the group has description, we should add some pixels
  var descriptionH = 0;
  if(this.hasSomeDescription(group)) {
    descriptionH = 20;
  }
  
  // Setup row animation states
  var rowAnimCfg = {
    // from : {
    //   height: function() {
    //      ROW_SHRUNK_H
    //   }
    // },
    from : {
      
    },
    to : {
      height: function() {
        var ret;
        if(group.state == kronos.GROUP_EXPANDING || group.state == kronos.GROUP_EXPANDED)
          ret = ROW_EXPANDED_H + descriptionH;
        else if(group.state == kronos.GROUP_SHRUNK || group.state == kronos.GROUP_SHRINKING)
          ret = ROW_SHRUNK_H;
        else if(group.state == kronos.GROUP_HIDING || group.state == kronos.GROUP_HIDDEN)
          ret = 0;
        else
          ret = ROW_SHRUNK_H;
        return ret;
      }
    }
  };
  row.setupAnimation(rowAnimCfg);
  
  // Setup scroller animation states
  var scrollerAnimCfg = {
    from : {
      height: IMG_SHRUNK_H,
      top : -17.5,
      left : 0
    },
    to : {
      height: ROW_EXPANDED_H + descriptionH,
      top : 0,
      left : 0
    }
  };
  scroller.setupAnimation(scrollerAnimCfg);
  this.setupGroupItemsAnimation(group);
  this.setupGroupItemsLeftPos(group);
}

GroupController.prototype.setupGroupItemsAnimation = function(group) {
  for(var i = 0; i < group.items.length; ++i) {
    var item = group.items[i];
    this.setupGroupItemAnimation(group, item);
  }
}

GroupController.prototype.setupGroupItemAnimation = function(group, item) {
  var itemAnim = {
    to : {
      width : function() {
        var ret;
        if(! item.visible)
          ret = 0;
        else if(group.state == kronos.GROUP_EXPANDING || group.state == kronos.GROUP_EXPANDED)
          ret = item.width;
        else if(group.state == kronos.GROUP_SHRUNK || group.state == kronos.GROUP_SHRINKING)
          ret = item.previewWidth;
        else if(group.state == kronos.GROUP_HIDING || group.state == kronos.GROUP_HIDDEN) {
          ret = item.visible ? item.previewWidth : 0;
        }
        else
          ret = item.previewWidth;
        return ret;
      },
      height : function() {
        var ret;
        if(group.state == kronos.GROUP_EXPANDING || group.state == kronos.GROUP_EXPANDED)
          ret = item.height;
        else
          ret = item.previewHeight;            
        return ret;
      },
      left : function() {
        var ret;
        if(group.state == kronos.GROUP_EXPANDING || group.state == kronos.GROUP_EXPANDED)
          ret = item.left;
        else
          ret = item.previewLeft;
        return ret;
      }
    }
  };
  item.setupAnimation(itemAnim);
}

GroupController.prototype.setupGroupItemsLeftPos = function(group) {
  var leftShr = 0,
      leftExp = 0;  
  for(var i = 0; i < group.items.length; ++i) {
    var groupItem = group.items[i];
    groupItem.previewLeft = leftShr;
    groupItem.left = leftExp;
    if(groupItem.visible) {
      leftShr += groupItem.previewWidth;
      leftExp += groupItem.width;
    }
  }
}

//
// FILTERS
//

GroupController.prototype.hookMenuItems = function() {
  var that = this;
  var filterDataFn = function(e) {
    var btnX = e.currentTarget;
    var btn = Y.one(btnX);
    var filterName;
    if(btn.hasClass('filter-all'))
      filterName = 'filter-all';
    else if(btn.hasClass('filter-logo'))
      filterName = 'filter-logo';
    else if(btn.hasClass('filter-web'))
      filterName = 'filter-web';
    else if(btn.hasClass('filter-design'))
      filterName = 'filter-design';
    else if(btn.hasClass('filter-foto'))
      filterName = 'filter-foto';
    else if(btn.hasClass('filter-publikace'))
      filterName = 'filter-publikace';
    
    Y.all('#menu li').removeClass('current');
    btn.addClass('current');
    
    if(filterName)
      that.filterGroups(filterName);
  }
  Y.on('click', filterDataFn, '.menu-item');
}

GroupController.prototype.filterGroups = function(filterName) {
  // At first we should convert the filter to some letter based filter
  var filter = FILTERS[filterName];
  if(filterName == 'filter-all')
    filter = 'all';

  for(var i = 0; i < this._groupNames.length; ++i) {
    var name = this._groupNames[i];
    var grp = this._groups[name];
    this.updateGroupFilter(grp, filter);
  }
}

GroupController.prototype.updateGroupFilter = function(group, filter) {
  // At first we should update the filter data
  this.updateGroupFilterData(group, filter);
  
  if(this.hasSomeItemsVisible(group)) {
    // And update group items left positions
    this.setupGroupItemsLeftPos(group);
    // Ensure that we can see the group
    this.showGroup(group);
    // We should hide all images that have flag visibility: hidden
    this.hideInvisibleImages(group);    
    // And update images positions
    this.setupGroupItemsCss(group);
  }
  else {
    // If there is no visible group item, we should hide the group
    this.hideGroup(group);
  }
}

GroupController.prototype.hasSomeItemsVisible = function(group) {
  for(var itemName in group.items) {
    var item = group.items[itemName];
    if(item.visible)
      return true;
  }
  return false;
}

GroupController.prototype.hideInvisibleImages = function(group) {
  for(var i = 0; i < group.items.length; ++i) {
    var item = group.items[i];
    var descNode = Y.one('#desc-' + item.name);
    if(item.visible) {
      descNode.setStyle('visibility', 'visible');
      descNode.setStyle('display', 'block');
    }
    else {
      descNode.setStyle('visibility', 'hidden');
      descNode.setStyle('display', 'none');
    }
  }
}

GroupController.prototype.setupGroupItemsCss = function(group) {
  for(var i = 0; i < group.items.length; ++i) {
    var item = group.items[i];
    // var node = Y.one('#' + item.name);
    // TODO: check if we are small or expanded
    // if(group.state == kronos.GROUP_SHRUNK || group.state == kronos.GROUP_SHRINKING)
    //   var newPos = item.previewLeft;
    // else
    //   var newPos = item.left;
    // node.setStyle('left', newPos + 'px');
    
    item.animate();
    
    var descNode = Y.one('#desc-' + item.name);
    descNode.setStyle('left', item.left + 'px')
  }
}

GroupController.prototype.updateGroupFilterData = function(group, filter) {
  for(var itemName in group.items) {
    var item = group.items[itemName];
    if(filter == 'all')
      item.visible = true;
    else
      item.visible = this.matchesFilter(item, filter);
  }
}

GroupController.prototype.matchesFilter = function(groupItem, filter) {
  var itemFilter = groupItem.filter;
  for(var i = 0; i < filter.length; ++i) {
    var filterChar = filter[i];
    if(itemFilter.indexOf(filterChar) >= 0)
      return true;
  }
  return false;
}

GroupController.prototype.hideGroup = function(group) {
  if(group.state != kronos.GROUP_HIDING && group.state != kronos.HIDDEN) {
    group.state = kronos.GROUP_HIDING;
    var node = Y.one('#row-' + group.name);
  
    var scroller = group.scroller;
    var row = group.row;
    scroller.animate();
    row.animate();
  }
//  node.setStyle('visibility', 'hidden');
//  node.setStyle('display', 'none');
}

GroupController.prototype.showGroup = function(group) {
  if(group.state == kronos.GROUP_HIDDEN || group.state == kronos.GROUP_HIDING) {
    group.state = kronos.GROUP_SHRINKING;
    var node = Y.one('#row-' + group.name);
  
    var scroller = group.scroller;
    var row = group.row;
    scroller.animate();
    row.animate();
    
    if(group.mouseOver)
      scroller.displayArrows(false);
  }
//  node.setStyle('visibility', 'visible');
//  node.setStyle('display', 'block');
}

//
//  DESCRIPTION
//

GroupController.prototype.hasSomeDescription = function(group) {
  for(var itemName in group.items) {
    var item = group.items[itemName];
    if(item.description && item.description.length > 0)
      return true;
  }
  
  return false;
}

GroupController.prototype.findGroup = function(nodeOrId) {
  var id = nodeOrId;
  
  if(typeof nodeOrId != 'string')
    id = nodeOrId.get('id');
  
  // Ok, so we have id, so now we should split it up
  var parts = id.split('_');
  var groupId = parts[0];
  var group = this._groups[groupId];
  return group;
}

GroupController.prototype.findGroupItem = function(nodeOrId) {
  var id = nodeOrId;
  
  if(typeof nodeOrId != 'string')
    id = nodeOrId.get('id');
  
  // Now find group
  var parts = id.split('_');
  var groupId = parts[0];
  var group = this._groups[groupId];
  
  // Now find the group item in the group
  var item = group.getItem(id);
  return item;
}

/**
 * Expands a group. Also shrinks the possibly expanded one.
 */
GroupController.prototype.expand = function(group) {
  // At first we should shrink the expanded group
  for(var groupName in this._groups) {
    var grp = this._groups[groupName];
    if(grp.state != kronos.GROUP_HIDDEN && grp.state != kronos.GROUP_HIDING) {
      if(grp.state == kronos.GROUP_EXPANDING || grp.state == kronos.GROUP_EXPANDED)
        this.shrink(grp, false);
    }
  }
  
  // TODO: shrink other expanded group
  var currentState = group.state;
  if(currentState == kronos.GROUP_SHRINKING) {
    this.stopGroupAnimation(group);
    this.doExpandGroup(group);
  }
  else if(currentState == kronos.GROUP_SHRUNK)
    this.doExpandGroup(group);
  // Otherwise we are already expanded or we are expanding, so do nothing! (-;
}

GroupController.prototype.shrink = function(group, hideBackground) {
  var currentState = group.state;
  if(currentState == kronos.GROUP_EXPANDING) {
    this.stopGroupAnimation(group);
    this.doShrinkGroup(group, hideBackground);
  }
  else if(currentState == kronos.GROUP_EXPANDED)
    this.doShrinkGroup(group, hideBackground);
  // Otherwise we are already shrunk or we are shrinking, so do nothing! (-;
}

/**
 * Actually performs expanding.
 */
GroupController.prototype.doExpandGroup = function(group) {
  var scroller = group.scroller;
  var row = group.row;
  
  group.state = kronos.GROUP_EXPANDING;
  row.animate(true);
  scroller.animate(true);
  for(var groupName in group.items) {
    var item = group.items[groupName];
    item.animate(true);
  }
  
  if(group.backgroundUrl) {
    var body = Y.one('body');
    body.setStyle('backgroundImage', 'url(\'' + group.backgroundUrl + '\')');
  }
}

/**
 * Actually perform shrink.
 */
GroupController.prototype.doShrinkGroup = function(group, hideBackground) {
  var scroller = group.scroller;
  var row = group.row;
  var scroller = group.scroller;
  
  group.scroller.displayArrows(false);
  group.state = kronos.GROUP_SHRINKING;
  row.animate(false);
  scroller.animate(false);
  for(var groupName in group.items) {
    var item = group.items[groupName];
    item.animate(false);
    var src = 'portfolio-small/' + item.fileName;
    var itemNode = Y.one('#' + item.name);
    itemNode.set('src', src);
  }
  
  if(hideBackground) {
    var body = Y.one('body');
    var url = 'url(\'backgrounds/default.png\')';
    body.setStyle('backgroundImage', url);
  }
}

GroupController.prototype.stopGroupAnimation = function(group) {
  var scroller = group.scroller;
  var row = group.row;
  
  scroller.stopAnimation();
  row.stopAnimation();
}

/**
 * This function should be a handler of clicking on the group.
 */
GroupController.prototype.groupClickHandler = function(group) {
  var currentState = group.state;
  if(currentState == kronos.GROUP_EXPANDED || currentState == kronos.GROUP_EXPANDING)
    group.shrink();
  else
    group.expand();
}

GroupController.prototype.endAnimationHandler = function(evt) {
  var group = evt.group;
  var currentState = group.state;
  if(currentState == kronos.GROUP_EXPANDING) {
    group.state = kronos.GROUP_EXPANDED;
    group.scroller.displayArrows(true);
    
    for(var i = 0; i < group.items.length; ++i) {
      var item = group.items[i];
      var itemNode = Y.one('#' + item.name);
      var src = 'portfolio/' + item.fileName;
      itemNode.set('src', src);
    }
  }
  else if(currentState == kronos.GROUP_SHRINKING) {
    for(var i = 0; i < group.items.length; ++i) {
      var item = group.items[i];
      var itemNode = Y.one('#' + item.name);
      var src;
      if(group.mouseOver)
        src = 'portfolio-small/' + item.fileName;
      else
        src = 'portfolio-smallgrey/' + item.fileName;
      itemNode.set('src', src);
    }
    group.state = kronos.GROUP_SHRUNK;
  }
  
  // Or there is no more possible cases
}

GroupController.prototype.mouseOverListener = function(evt) {
  var group = evt.group;
  if(group.state == kronos.GROUP_SHRUNK || group.state == kronos.GROUP_SHRINKING) {
    // We should change the urls of the images from gray ones to colour ones
    for(var itemName in group.items) {
      var item = group.items[itemName];
      var itemNode = Y.one('#' + item.name);
      var src = 'portfolio-small/' + item.fileName;
      itemNode.set('src', src);
    }
  }
  
  group.mouseOver = true;
}

GroupController.prototype.mouseOutListener = function(evt) {
  var group = evt.group;
  if(group.state == kronos.GROUP_SHRUNK || group.state == kronos.GROUP_SHRINKING) {
    // We should change the urls of the images from gray ones to colour ones
    for(var itemName in group.items) {
      var item = group.items[itemName];
      var itemNode = Y.one('#' + item.name);
      var src = 'portfolio-smallgrey/' + item.fileName;
      itemNode.set('src', src);
    }
  }
  
  group.mouseOver = false;
}

/**
 * This function should be a handler for clicing on the group item.
 */
GroupController.prototype.groupItemClickHandler = function(groupItem) {
  var group = groupItem.group;
  this.groupClickHandler(group);
}

kronos.GroupController = GroupController;

}, '1.0.0' /* module version */, {
  requires: ['base', 'group', 'row', 'scroller']
});
