//
//  WBOverviewPanel.mm
//  MySQLWorkbench
//
//  Created by Alfredo Kojima on 6/Oct/08.
//  Copyright 2008 Sun Microsystems Inc. All rights reserved.
//

#import "WBOverviewPanel.h"
#import "MTogglePane.h"
#import "WBOverviewListController.h"
#import "WBSchemaTabView.h"
#import "WBSchemaTabItem.h"
#import "WBOverviewComponents.h"
#import "MVerticalLayoutView.h"

#import "WBOverviewWorkbenchCentral.h"

#include "workbench/wb_context.h"

@interface WBOverviewBackgroundView : MVerticalLayoutView
{
  NSImage *bgImage;
  NSImage *shadowImage;
}
@end

static void DrawTiledImage(NSImage *image, NSRect rect, BOOL composite)
{
  NSSize imageSize= [image size];
  NSRect imageRect;
  
  imageRect.origin= NSMakePoint(0, 0);
  imageRect.size= imageSize;
  for (CGFloat y= 0; y < rect.size.height; y+= imageSize.height)
  {
    for (CGFloat x= 0; x < rect.size.width; x+= imageSize.width)
    {
      [image drawAtPoint:NSMakePoint(rect.origin.x+x, rect.origin.y+y) 
                fromRect:imageRect
               operation:composite ? NSCompositeSourceOver : NSCompositeCopy 
                fraction:1.0];
    }
  }
}

@implementation WBOverviewBackgroundView

- (id)initWithFrame:(NSRect)rect
{
  if ((self= [super initWithFrame:rect]) != nil)
  {
    bgImage= [NSImage imageNamed:@"background.png"];
    shadowImage= [NSImage imageNamed:@"background_top_shadow.png"];
    [shadowImage setFlipped:YES];
  }
  return self;
}

- (void)dealloc
{
  [bgImage release];
  [shadowImage release];
  [super dealloc];
}


- (void)drawRect:(NSRect)rect
{  
  rect= [self frame];
  if (usedHeight < NSHeight(rect))
  {
    DrawTiledImage(bgImage, rect, NO);

    rect.size.height= usedHeight;
    rect.origin.y= 0;
    [[NSColor whiteColor] set];
    NSRectFill(rect);
    
    rect.origin.y= usedHeight;
    rect.size.height= [shadowImage size].height;
    DrawTiledImage(shadowImage, rect, YES);
  }
}

@end





@implementation WBOverviewPanel

static NSString *stringFromNodeId(const bec::NodeId &node)
{
  return [NSString stringWithCString:node.repr().c_str()];
}


- (id)initWithBE:(wb::OverviewBE*)overview
{
  if ((self= [super init]) != nil)
  {
    _overview= overview;
    _overview->set_frontend_data(self);

    _scrollView= [[NSScrollView alloc] initWithFrame: NSMakeRect(0,0, 300, 300)];
    [_scrollView setHasVerticalScroller:YES];
    [_scrollView setHasHorizontalScroller:NO];
    [_scrollView setBorderType:NSBezelBorder];
    
    _contentView= [[WBOverviewBackgroundView alloc] initWithFrame: NSMakeRect(0, 0, 
                                                                              [_scrollView contentSize].width,
                                                                              [_scrollView contentSize].height)];
    [_contentView setAutoresizingMask:NSViewWidthSizable||NSViewMaxYMargin|NSViewMinXMargin|NSViewMaxXMargin];
    [_scrollView setDocumentView:_contentView];
    
    _itemContainers= [[NSMutableDictionary alloc] init];
  }
  return self;
}


- (void)dealloc
{
  delete _lastFoundNode;
  [_searchText release];
  [_itemContainers release];
  [_scrollView release];
  [super dealloc];
}


- (void)searchString:(NSString*)text
{
  if (_searchText && [text hasPrefix:_searchText])
  {
    // nothing
  }
  else
  {
    delete _lastFoundNode;
    _lastFoundNode= 0;
  }
  
  [_searchText release];
  _searchText= [text retain];
  
  bec::NodeId node= _overview->search_child_item_node_matching(bec::NodeId(), 
                                                             _lastFoundNode ? *_lastFoundNode : bec::NodeId(),
                                                             [_searchText UTF8String]);
  if (node.is_valid())
  {
    _lastFoundNode= new bec::NodeId(node);
    
    id container= [_itemContainers objectForKey:stringFromNodeId(_overview->get_parent(node))];
    
    for (id cont in [_itemContainers objectEnumerator])
    {
      if (cont == container)
      {
        if ([container respondsToSelector:@selector(selectNode:)])
          [container selectNode: *_lastFoundNode];
      }
      else
      {
        if ([cont respondsToSelector:@selector(clearSelection)])
          [cont clearSelection];
      }
    }
    
    std::string label;
    _overview->get_field(*_lastFoundNode, wb::OverviewBE::Label, label);
    _overview->get_wb()->get_grt_manager()->replace_status_text(strfmt(_("Found '%s'"), label.c_str()));
  }
  else
  {
    delete _lastFoundNode;
    _lastFoundNode= 0;
    _overview->get_wb()->get_grt_manager()->replace_status_text(_("No matches found."));
  }
}


- (NSView*)topView
{
  return _scrollView;
}


- (NSString*)title
{  
  try
  {
    std::string title;

    _overview->get_field(bec::NodeId(), wb::OverviewBE::Label, title);
  
    return [NSString stringWithUTF8String: title.c_str()];
  }
  catch (...)
  {
    return @"Overview";
  }
}


- (NSString*)identifier
{
  return [NSString stringWithUTF8String: _overview->identifier().c_str()];
}


- (bec::UIForm*)formBE
{
  return _overview;
}


- (wb::OverviewBE*)backend
{
  return _overview;
}


- (void)setMenuManager:(WBMenuManager*)manager
{
  _menuManager= manager;
}


- (WBMenuManager*)menuManager
{
  return _menuManager;
}


- (void)refreshAll
{
  for (MTogglePane *item in [_contentView subviews])
  {
    id view= [item contentView];
    
    if ([view respondsToSelector:@selector(refreshChildren)])
      [view refreshChildren];
  }
}


- (void)rebuildAll
{
  [_itemContainers removeAllObjects];
  [self buildMainSections];
  
  [self refreshAll];
}


- (void)registerContainer:(id)container
                  forItem:(NSString*)item
{
  [_itemContainers setObject:container forKey:item];
}


- (void)unregisterContainerForItem:(NSString*)item
{
  [_itemContainers removeObjectForKey:item];
}


- (void)refreshNode:(const bec::NodeId&)node
{
  id container= [_itemContainers objectForKey:stringFromNodeId(node)];

  if (container && [container respondsToSelector:@selector(refreshInfo)])
    [container refreshInfo];
  else
  {
    container= [_itemContainers objectForKey:stringFromNodeId(_overview->get_parent(node))];
  
    if ([container respondsToSelector:@selector(refreshChildInfo:)])
      [container refreshChildInfo:node];
    else
      NSLog(@"node %s does not handle refreshing", node.repr().c_str());
  }
}


- (void)refreshNodeChildren:(const bec::NodeId&)node
{
  if (!node.is_valid())
  {
    [self rebuildAll];
  }
  else
  {
    int type;
        
    _overview->get_field(node, wb::OverviewBE::ChildNodeType, type);
    
    switch ((wb::OverviewBE::OverviewNodeType)type)
    {
      case wb::OverviewBE::OGroup:
        [[_itemContainers objectForKey:stringFromNodeId(node)] refreshChildren];
        break;
        
      case wb::OverviewBE::OItem:
        [[_itemContainers objectForKey:stringFromNodeId(node)] refreshChildren];
        break;
        
      default: break;
    }
  }
}


static int first_child_type(wb::OverviewBE *overview, const bec::NodeId &node)
{
  if (overview->count_children(node) > 0)
  {
    int type= -1;
    overview->get_field(overview->get_child(node, 0), wb::OverviewBE::NodeType, type);
    return type;
  }
  return -1;
}


- (NSView*)buildDivision:(const bec::NodeId&)node
                  inPane:(MTogglePane*)pane
{
  int child_type;
  // Get the type of the item we are adding. It could be division (EER Diagrams, Physical Schemata)
  // or group (database, ...)
  // or TODO: add comments here for the rest of the stuff
  // type is modified inside the get_field
  _overview->get_field(node, wb::OverviewBE::ChildNodeType, child_type);
  
  if (child_type == wb::OverviewBE::OGroup)
  {
    WBOverviewGroupContainer *groups= [[[WBOverviewGroupContainer alloc] initWithOverview:self
                                                                                   nodeId:node] autorelease];
    [pane setContentView: groups];
    
    // Add special buttons used to manipulate content or display of this container.
    /*
    [pane addButton: [NSImage imageNamed: @"collapsing_panel_grid_large_icons.png"]
         withAction: @selector(setLargeIconMode)
             target: groups];
    [pane addButton: [NSImage imageNamed: @"collapsing_panel_grid_small_icons.png"]
         withAction: @selector(setSmallIconMode)
             target: groups];
    [pane addButton: [NSImage imageNamed: @"collapsing_panel_grid_details.png"]
         withAction: @selector(setDetailsMode)
             target: nil]; // Leave target nil to disable the button.
     */
    [pane addButton: [NSImage imageNamed: @"collapsing_panel_header_tab_add.png"]
         withAction: @selector(performGroupAdd:)
             target: groups];
    [pane addButton: [NSImage imageNamed: @"collapsing_panel_header_tab_del.png"]
         withAction: @selector(performGroupDelete:)
             target: groups];
    
    [_itemContainers setObject:groups forKey:[NSString stringWithCString:node.repr().c_str()]];
    
    [groups buildChildren];
    
    return groups;
  }
  else if (child_type == wb::OverviewBE::OItem)
  {
    WBOverviewItemContainer *itemList= [[[WBOverviewItemContainer alloc] initWithOverview:self
                                                                                   nodeId:node] autorelease];
    
    [_itemContainers setObject:itemList forKey:[NSString stringWithCString:node.repr().c_str()]];
    
    [pane setContentView: itemList];
    
    return itemList;
  }
  else if (child_type == wb::OverviewBE::OSection)
  {
    WBOverviewGroup *group= [[[WBOverviewGroup alloc] initWithOverview:self nodeId:node tabItem:nil] autorelease];
    
    [_itemContainers setObject:group forKey:[NSString stringWithUTF8String:node.repr().c_str()]];
    
    [group buildChildren];
    
    [pane setContentView:group];
    
    return group;
  }
  else if (child_type == wb::OverviewBE::OSpecial)
  {
    // special header
    [NSBundle loadNibNamed: @"WorkbenchCentralSplash" owner: self];
    
    [pane setContentView: workbenchCentral];
    
    [workbenchCentral setOverview: self];
    
    return workbenchCentral;
  }
  
  return nil;
}


- (void)buildMainSections
{
  bec::NodeId root, node;
  CGFloat width= NSWidth([_contentView frame]);

  for (NSView *subview in [[_contentView subviews] reverseObjectEnumerator])
    [subview removeFromSuperview];

  _overview->refresh();
  for (int i= 0; i < _overview->count_children(root); i++)
  {
    std::string label;
    wb::OverviewBE::OverviewNodeType nodeType;
    int expanded;

    node= _overview->get_child(root, i);

    _overview->get_field(node, wb::OverviewBE::Label, label);
    _overview->get_field(node, wb::OverviewBE::NodeType, (int&)nodeType);
    _overview->get_field(node, wb::OverviewBE::Expanded, expanded);

    if (nodeType == wb::OverviewBE::ODivision)
    {
      MTogglePane *pane= [[[MTogglePane alloc] initWithFrame:NSMakeRect(0, 0, width, 100)] autorelease];
      [pane setLabel:[NSString stringWithUTF8String:label.c_str()]];
      [pane setAutoresizingMask:NSViewWidthSizable|NSViewMaxYMargin];
      [_contentView addSubview:pane];
  
      id view= [self buildDivision:node
                            inPane:pane];
      if (view)
      { 
        [pane setExpanded:expanded!=0];
        
       // if ([view respondsToSelector:@selector(refreshChildren)])
        //  [view refreshChildren];
      }
    }
    else
    {
      NSLog(@"ERROR: unexpected node type in Overview");
    }
  }
  [_contentView relayout];
}

@end
