// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2011 Strobe Inc. and contributors.
//            Portions ©2008-2011 Apple Inc. All rights reserved.
// License:   Licensed under MIT license (see license.js)
// ==========================================================================

sc_require("views/workspace");

/**
  @static
  @type String
  @constant
*/
SC.TO_LEFT = "TOLEFT";

/**
  @static
  @type String
  @constant
*/
SC.TO_RIGHT = "TORIGHT";


/** @class

  NavigationView is very loosely based on UINavigationController:
  that is, it implements a push/pop based API. 
  
  NavigationView checks if the view is NavigationBuildable--that is, if it has 
  
  Views may specify a topToolbar or bottomToolbar property. These will become the
  top or bottom toolbars of the NavigationView (which is, incidentally, a WorkspaceView).
  
  Of course, this process is animated...
  
  @author Alex Iskander
  @extends SC.WorkspaceView
  @since SproutCore 1.4
*/
SC.NavigationView = SC.WorkspaceView.extend(
/** @scope SC.NavigationView.prototype */ {
  
  /** @private */
  _views: null,
  
  /** @private */
  _current: null,
  
  /**
    @type SC.View
    @default SC.View
  */
  navigationContentView: SC.View,
  
  /** @private */
  init: function() {
    arguments.callee.base.apply(this,arguments);
    this._views = [];
  },
  
  /** @private */
  createChildViews: function() {
    arguments.callee.base.apply(this,arguments);
    
    // get the content
    var content = this.get("navigationContentView");
    
    // instantiate if needed
    if (content.isClass) content = this.createChildView(content);
    
    // set internal values
    this._defaultContent = this.navigationContentView = content;
    
    // append to the content view
    this.contentView.appendChild(content);
  },
  
  /** @private */
  changeNavigationContent: function(view) {
    var top = null, bottom = null;
    
    // find top and bottom toolbars if we are setting it to a view
    if (view) {
      top = view.get("topToolbar"); 
      bottom = view.get("bottomToolbar");
    }
    
    // instantiate top if needed
    if (top && top.isClass) {
      view.set("topToolbar", top = top.create());
    }
    
    // and now bottom
    if (bottom && bottom.isClass) {
      view.set("bottomToolbar", bottom = bottom.create());
    }
    
    
    // batch property changes for efficiency
    this.beginPropertyChanges();
    
    // update current, etc. etc.
    this._current = view;
    this.set("navigationContentView", view ? view : this._defaultContent);
    
    // set the top/bottom appropriately
    this.set("topToolbar", top);
    this.set("bottomToolbar", bottom);
    
    // and we are done
    this.endPropertyChanges();
  },
  
  /**
    Pushes a view into the navigation view stack. The view may have topToolbar and bottomToolbar properties.
    
    @param {SC.View} view The view to display
  */
  push: function(view) {
    this._currentDirection = this._current ? SC.TO_LEFT : null;
    
    // add current view to the stack (if needed)
    if (this._current) this._views.push(this._current);
    
    // update content now...
    this.changeNavigationContent(view);
  },
  
  /**
    Pops the current view off the navigation view stack.
  */
  pop: function() {
    this._currentDirection = SC.TO_RIGHT;
    
    // pop the view
    var view = this._views.pop();
    
    // set new (old) content view
    this.changeNavigationContent(view);
  },
  
  /**
    Pops to the specified view on the navigation view stack; the view you pass will become the current view.
    
    @param {SC.View} toView The view to display
  */
  popToView: function(toView) {
    this._currentDirection = SC.TO_RIGHT;
    var views = this._views,
        idx = views.length - 1, 
        view = views[idx];
    
    // loop back from end
    while (view && view !== toView) {
      this._views.pop();
      idx--;
      view = views[idx];
    }
    
    // and change the content
    this.changeNavigationContent(view);
  },
  
  /** @private */
  topToolbarDidChange: function() {
    var active = this.activeTopToolbar, replacement = this.get("topToolbar");
    
    // if we have an active toolbar, set the build direction and build out
    if (active) {
      if (this._currentDirection !== null) {
        active.set("buildDirection", this._currentDirection);
        this.buildOutChild(active);
      } else {
        this.removeChild(active);
      }
    }
    
    // if we have a new toolbar, set the build direction and build in
    if (replacement) {
      if (this._currentDirection !== null) {
        replacement.set("buildDirection", this._currentDirection);
        this.buildInChild(replacement);
      } else {
        this.appendChild(replacement);
      }
    }
    
    // update, and queue retiling
    this.activeTopToolbar = replacement;
    this.invokeOnce("childDidChange");
  }.observes("topToolbar"),
  
  /** @private */
  bottomToolbarDidChange: function() {
    var active = this.activeBottomToolbar, replacement = this.get("bottomToolbar");
    
    if (active) {
      if (this._currentDirection !== null) {
        active.set("buildDirection", this._currentDirection);
        this.buildOutChild(active);
      } else {
        this.removeChild(active);
      }
    }
    if (replacement) {
      if (this._currentDirection !== null) {
        replacement.set("buildDirection", this._currentDirection);
        this.buildInChild(replacement);
      } else {
        this.appendChild(replacement);
      }
    }
    
    this.activeBottomToolbar = replacement;
    this.invokeOnce("childDidChange");
  }.observes("topToolbar"),
  
  /** @private */
  contentViewDidChange: function() {
    var active = this.activeNavigationContentView, replacement = this.get("navigationContentView");
    
    // mix in navigationbuilder if needed
    if (!replacement.isNavigationBuilder) {
      replacement.mixin(SC.NavigationBuilder);
    }
    
    // tiling really needs to happen _before_ animation
    // so, we set "pending" and queue tiling.
    this._pendingBuildOut = active;
    this._pendingBuildIn = replacement;
    
    this.activeNavigationContentView = replacement;
    this.invokeOnce("childDidChange");
  }.observes("navigationContentView"),
  
  /** @private */
  childDidChange: function() {
    var replacement = this._pendingBuildIn, active = this._pendingBuildOut;
    if (active) {
      if (this._currentDirection !== null) {
        active.set("buildDirection", this._currentDirection);
        this.contentView.buildOutChild(active);
      } else {
        this.contentView.removeChild(active);
      }
    }

    this._scws_tile();
    
    if (replacement) {
      if (this._currentDirection !== null) {
        replacement.set("buildDirection", this._currentDirection);
        this.contentView.buildInChild(replacement);
      } else {
        this.contentView.appendChild(replacement);
      }
    }
  }
  
});
