// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/browser/ui/cocoa/sidebar_controller.h"

#include <algorithm>

#include <Cocoa/Cocoa.h>

#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/sidebar/sidebar_manager.h"
#import "chrome/browser/ui/cocoa/view_id_util.h"
#include "chrome/common/pref_names.h"
#include "content/browser/tab_contents/tab_contents.h"

namespace {

// By default sidebar width is 1/7th of the current page content width.
const CGFloat kDefaultSidebarWidthRatio = 1.0 / 7;

// Never make the web part of the tab contents smaller than this (needed if the
// window is only a few pixels wide).
const int kMinWebWidth = 50;

}  // end namespace


@interface SidebarController (Private)
- (void)showSidebarContents:(TabContents*)sidebarContents;
- (void)resizeSidebarToNewWidth:(CGFloat)width;
@end


@implementation SidebarController

- (id)initWithDelegate:(id<TabContentsControllerDelegate>)delegate {
  if ((self = [super init])) {
    splitView_.reset([[NSSplitView alloc] initWithFrame:NSZeroRect]);
    [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
    [splitView_ setVertical:YES];
    [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
    [splitView_ setDelegate:self];

    contentsController_.reset(
        [[TabContentsController alloc] initWithContents:NULL
                                               delegate:delegate]);
  }
  return self;
}

- (void)dealloc {
  [splitView_ setDelegate:nil];
  [super dealloc];
}

- (NSSplitView*)view {
  return splitView_.get();
}

- (NSSplitView*)splitView {
  return splitView_.get();
}

- (void)updateSidebarForTabContents:(TabContents*)contents {
  // Get the active sidebar content.
  if (SidebarManager::GetInstance() == NULL)  // Happens in tests.
    return;

  TabContents* sidebarContents = NULL;
  if (contents && SidebarManager::IsSidebarAllowed()) {
    SidebarContainer* activeSidebar =
        SidebarManager::GetInstance()->GetActiveSidebarContainerFor(contents);
    if (activeSidebar)
      sidebarContents = activeSidebar->sidebar_contents();
  }

  TabContents* oldSidebarContents = [contentsController_ tabContents];
  if (oldSidebarContents == sidebarContents)
    return;

  // Adjust sidebar view.
  [self showSidebarContents:sidebarContents];

  // Notify extensions.
  SidebarManager::GetInstance()->NotifyStateChanges(
      oldSidebarContents, sidebarContents);
}

- (void)ensureContentsVisible {
  [contentsController_ ensureContentsVisible];
}

- (void)showSidebarContents:(TabContents*)sidebarContents {
  [contentsController_ ensureContentsSizeDoesNotChange];

  NSArray* subviews = [splitView_ subviews];
  if (sidebarContents) {
    DCHECK_GE([subviews count], 1u);

    // Native view is a TabContentsViewCocoa object, whose ViewID was
    // set to VIEW_ID_TAB_CONTAINER initially, so change it to
    // VIEW_ID_SIDE_BAR_CONTAINER here.
    view_id_util::SetID(
        sidebarContents->GetNativeView(), VIEW_ID_SIDE_BAR_CONTAINER);

    CGFloat sidebarWidth = 0;
    if ([subviews count] == 1) {
      // Load the default split offset.
      sidebarWidth = g_browser_process->local_state()->GetInteger(
          prefs::kExtensionSidebarWidth);
      if (sidebarWidth < 0) {
        // Initial load, set to default value.
        sidebarWidth =
            NSWidth([splitView_ frame]) * kDefaultSidebarWidthRatio;
      }
      [splitView_ addSubview:[contentsController_ view]];
    } else {
      DCHECK_EQ([subviews count], 2u);
      sidebarWidth = NSWidth([[subviews objectAtIndex:1] frame]);
    }

    // Make sure |sidebarWidth| isn't too large or too small.
    sidebarWidth = std::min(sidebarWidth,
                            NSWidth([splitView_ frame]) - kMinWebWidth);
    DCHECK_GE(sidebarWidth, 0) << "kMinWebWidth needs to be smaller than "
                               << "smallest available tab contents space.";
    sidebarWidth = std::max(static_cast<CGFloat>(0), sidebarWidth);

    [self resizeSidebarToNewWidth:sidebarWidth];
  } else {
    if ([subviews count] > 1) {
      NSView* oldSidebarContentsView = [subviews objectAtIndex:1];
      // Store split offset when hiding sidebar window only.
      int sidebarWidth = NSWidth([oldSidebarContentsView frame]);
      g_browser_process->local_state()->SetInteger(
          prefs::kExtensionSidebarWidth, sidebarWidth);
      [oldSidebarContentsView removeFromSuperview];
      [splitView_ adjustSubviews];
    }
  }

  [contentsController_ changeTabContents:sidebarContents];
}

- (void)resizeSidebarToNewWidth:(CGFloat)width {
  NSArray* subviews = [splitView_ subviews];

  // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
  // but I can't figure out how to use it. Manually resize web and sidebar.
  // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
  // category on NSSplitView to handle manual resizing.
  NSView* sidebarView = [subviews objectAtIndex:1];
  NSRect sidebarFrame = [sidebarView frame];
  sidebarFrame.size.width = width;
  [sidebarView setFrame:sidebarFrame];

  NSView* webView = [subviews objectAtIndex:0];
  NSRect webFrame = [webView frame];
  webFrame.size.width =
      NSWidth([splitView_ frame]) - ([splitView_ dividerThickness] + width);
  [webView setFrame:webFrame];

  [splitView_ adjustSubviews];
}

// NSSplitViewDelegate protocol.
- (BOOL)splitView:(NSSplitView *)splitView
    shouldAdjustSizeOfSubview:(NSView *)subview {
  // Return NO for the sidebar view to indicate that it should not be resized
  // automatically.  The sidebar keeps the width set by the user.
  if ([[splitView_ subviews] indexOfObject:subview] == 1)
    return NO;
  return YES;
}

@end