/* 
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#import "WBModelSidebarController.h"
#import "GRTTreeDataSource.h"
#import "GRTListDataSource.h"
#import "MCanvasViewer.h"
#import "WBObjectPropertiesController.h"
#import "MOutlineView.h"
#import "MTextImageCell.h"
#import "GRTIconCache.h"

#include "workbench/wb_context.h"
#include "workbench/wb_context_ui.h"
#include "model/wb_history_tree.h"
#include "model/wb_model_diagram_form.h"
#include "model/wb_user_datatypes.h"
#include "model/wb_context_model.h"

#import "mforms/../cocoa/MFView.h"
#import "MCPPUtilities.h"

#include "grtdb/db_object_helpers.h"


@implementation WBModelSidebarController

- (void)setupWithWBContextUI:(wb::WBContextUI*)wbui
{
  _wbui= wbui;
 
  /*
  [[NSNotificationCenter defaultCenter] addObserver: self
                                           selector: @selector(menuAction:)
                                               name: NSMenuActionNotification
                                             object: nil];
  */
  [catalogOutline setDoubleAction:@selector(activateCatalogItem:)];
  [catalogOutline setTarget:self];
  
  // set backend model for catalog DS
  [catalogDS setHidesRootNode:YES];
  [catalogDS setDragDelegate:self];
  
  [catalogDS setTreeModel: _wbui->get_catalog_tree()];
  
  // set backend for usertype ds
  _udtlist = _wbui->get_wb()->get_model_context()->create_user_type_list();
  NSView *udtview = nsviewForView(_udtlist);
  [userTypesTab setView: udtview];

  // set backend for history DS
  _history = _wbui->get_wb()->get_model_context()->create_history_tree();
  NSView *hview = nsviewForView(_history);
  [historyTab setView: hview];

  [self refresh];  
}


- (void)reuseShareableDataSourcesFrom:(WBModelSidebarController*)sidebar
{
  if (sidebar)
  {
    catalogDS = sidebar->catalogDS;
  }
  else
  {
    catalogDS = nil;
  }
  
  [catalogOutline setDataSource: catalogDS];
  [catalogOutline setDelegate: self];
}


- (void)dealloc
{
  delete _udtlist;
  delete _history;
  
  [super dealloc];
}


- (void)invalidate
{
  // since performSelectorOnMainThread could have pending refreshes, set _wbui to nil
  _wbui= 0;
}


- (void)setZoom:(id)x
{
  NSLog(@"here");
}

//--------------------------------------------------------------------------------------------------

/**
 * Triggered if the underlying outline view was told the backend does not handle the specific
 * menu command (usually the case for pure UI related tasks). Thus handle them here.
 */
- (void) menuAction: (NSNotification*) notification
{
  id sender = [notification object];
  NSString* command = [sender representedObject];
  
  if ([command compare: @"refreshCatalog"] == NSOrderedSame)
    [self refreshCatalogTree];
}

//--------------------------------------------------------------------------------------------------

- (void) updateForSelectionChange
{
  // XXX
}

//--------------------------------------------------------------------------------------------------

- (void)refresh
{
  [self refreshCatalogTree];
}

- (void)refreshCatalogTree
{
  if (_wbui)
  {
    NSPoint pos = [[[catalogOutline enclosingScrollView] contentView] documentVisibleRect].origin;
    NSIndexSet *selectedIndexes = [[catalogOutline selectedRowIndexes] copy];
    
    _wbui->get_catalog_tree()->refresh();
    [catalogOutline reloadData];
  
    [catalogOutline expandItem:[catalogOutline itemAtRow: 0]];
    // expand everything from bottom to top so that only the folders get expanded
    for (int i= [catalogOutline numberOfRows]-1; i >= 1; --i)
    {
      // force expansion of node
      [catalogOutline collapseItem:[catalogOutline itemAtRow:i]];
      [catalogOutline expandItem:[catalogOutline itemAtRow:i]];
    }
    
    [[[catalogOutline enclosingScrollView] contentView] scrollToPoint: pos];
    [[catalogOutline enclosingScrollView] reflectScrolledClipView: [[catalogOutline enclosingScrollView] contentView]];
    
    [catalogOutline selectRowIndexes: selectedIndexes byExtendingSelection: NO];
    [selectedIndexes release];
  }
}


- (BOOL)dataSource:(id)source
        writeItems:(NSArray*)items
      toPasteboard:(NSPasteboard*)pboard
{
  if (source == catalogDS)
  {
    std::list<db_DatabaseObjectRef> objects;
    std::string path;
    
    for (id item in items)
    {
      bec::NodeId node= [source nodeIdForItem:item];
      grt::ValueRef value(_wbui->get_catalog_tree()->get_node_value(node));

      if (value.is_valid() && db_DatabaseObjectRef::can_wrap(value))
      {
        objects.push_back(db_DatabaseObjectRef::cast_from(value));
        
        path= "/wb/doc/physicalModels/0/catalog/schemata" + _wbui->get_catalog_tree()->get_path_for_node(node, true);
      }
    }

    std::string str= bec::CatalogHelper::dbobject_list_to_dragdata(objects);
    if (!str.empty())
    {
      [pboard declareTypes:[NSArray arrayWithObjects:
                            @"x-mysql-wb/db.DatabaseObject", 
                            NSStringPboardType,
                            nil]
                     owner:nil];

      [pboard setString:[NSString stringWithCPPString: str.c_str()]
                forType:@"x-mysql-wb/db.DatabaseObject"];
      [pboard setString:[NSString stringWithCPPString: path.c_str()]
                forType:NSStringPboardType];
      return YES;
    }
  }
  return NO;
}


- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
  if (outlineView == catalogOutline)
  {
    if ([cell isKindOfClass:[MTextImageCell class]])
    {
      bec::NodeId node_id= [catalogDS nodeIdForItem:item];
      bec::TreeModel *tree= [catalogDS treeModel];
      bec::IconId icon_id= tree->get_field_icon(node_id, [[tableColumn identifier] integerValue], bec::Icon16);
      
      NSImage *image= [[GRTIconCache sharedIconCache] imageForIconId:icon_id];
      
      if (icon_id != 0 && !image && tree->is_expandable(node_id))
      {
        image= [[GRTIconCache sharedIconCache] imageForFolder:bec::Icon16];
      }
      
      if (icon_id != 0)
        [cell setImage:image];
      else
        [cell setImage:nil];
      
      std::string tmp;
      tree->get_field(node_id, 1, tmp);
      if (tmp.empty())
        [cell setFont: [NSFont systemFontOfSize: [NSFont smallSystemFontSize]]];
      else
        [cell setFont: [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]]];
    }
  }
}


- (void)outlineViewItemWillExpand:(NSNotification *)notification
{
  id datasource = [notification.object dataSource];
  if ([datasource conformsToProtocol: @protocol(NSOutlineViewDelegate)])
    [datasource outlineViewItemWillExpand: notification];
}


- (void)outlineViewItemDidCollapse:(NSNotification *)notification
{
  id datasource = [notification.object dataSource];
  if ([datasource conformsToProtocol: @protocol(NSOutlineViewDelegate)])
    [datasource outlineViewItemDidCollapse: notification];
}


- (IBAction)activateCatalogItem:(id)sender
{
  _wbui->get_catalog_tree()->activate_node([catalogDS nodeIdForItem:[catalogOutline itemAtRow: [catalogOutline clickedRow]]]);
}


//--------------------------------------------------------------------------------------------------

- (NSOutlineView*) catalogOutline
{
  return catalogOutline;
}

//--------------------------------------------------------------------------------------------------

- (GRTTreeDataSource*) catalogDS
{
  return catalogDS;
}
@end
