/* 
 * Copyright (c) 2008, 2014, 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 "MFFileChooser.h"

#import "MFView.h"
#import "MFMForms.h"

@implementation MFFileChooserImpl

- (id)initWithObject: (mforms::FileChooser*) chooser type: (mforms::FileChooserType) type showHidden: (BOOL) showHidden
{
  self= [super init];
  if (self)
  {
    mOwner= chooser;
    mOwner->set_data(self);
    
    mOptionControls = [[NSMutableDictionary alloc] init];
    
    switch (type)
    {
      case mforms::OpenFile:
      {
        NSOpenPanel *panel= [[NSOpenPanel openPanel] retain];
        mPanel= panel;
        [panel setCanChooseDirectories:NO];
        [panel setCanChooseFiles:YES];
        [panel setExtensionHidden: NO];
        
        if (showHidden)
          [panel setShowsHiddenFiles: YES];
        break;
      }
      
      case mforms::SaveFile:
        mPanel= [[NSSavePanel savePanel] retain];
        [mPanel setCanCreateDirectories: YES];
        [mPanel setExtensionHidden: NO];
        [mPanel setDelegate: self];
        break;

      case mforms::OpenDirectory:
      {
        NSOpenPanel *panel= [[NSOpenPanel openPanel] retain];
        mPanel= panel;
        [panel setCanChooseDirectories:YES];
        [panel setCanChooseFiles:NO];
        [panel setExtensionHidden: NO];

        if (showHidden)
          [panel setShowsHiddenFiles: YES];
        break;
      }
    }
    [mPanel setAllowsOtherFileTypes:YES];
  }
  return self;
}


- (NSPopUpButton*)addSelectorOption: (NSArray*)values label: (NSString*)label
{
  if (!mOptionsView)
    mOptionsView = [[NSView alloc] initWithFrame: NSMakeRect(0, 0, 420, 30)];
  
  NSPopUpButton *pop = [[[NSPopUpButton alloc] initWithFrame: NSMakeRect(0, 0, 250, 20)] autorelease];
  for (int c = [values count], i = 0; i < c; i+= 2)
  {
    [pop addItemWithTitle: [values objectAtIndex: i]];
    [[pop lastItem] setRepresentedObject: [values objectAtIndex: i+1]];
  }
  [pop sizeToFit];
  
  NSTextField *text = [[[NSTextField alloc] initWithFrame: NSMakeRect(0, 0, 150, 20)] autorelease];
  [text setStringValue: label];
  [text setEditable: NO];
  [text setDrawsBackground: NO];
  [text setBordered: NO];
  [text setAlignment: NSRightTextAlignment];
  [mOptionsView addSubview: text];
  [text setAutoresizingMask: NSMinXEdge|NSMaxYEdge];
  [mOptionsView addSubview: pop];
  [pop setAutoresizingMask: NSMinXEdge|NSMaxYEdge|NSViewWidthSizable|NSMaxXEdge];
  
  [mOptionsView setFrameSize: NSMakeSize(NSWidth([mOptionsView frame]), ([mOptionControls count]+1) * 25 + 20)];
  float y = NSHeight([mOptionsView frame]) - 10;
  for (id view in [mOptionsView subviews])
  {
    if ([view isKindOfClass: [NSTextField class]])
    {
      y -= 25;
      [view setFrameOrigin: NSMakePoint(0, y)];
    }
    else
      [view setFrameOrigin: NSMakePoint(154, y)];
  }
  return pop;
}


- (void)dealloc
{
  [mOptionsView release];
  [mOptionControls release];
  [mPanel release];
  [super dealloc];
}


- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
{
  NSPopUpButton *fileTypeMenu = [mOptionControls objectForKey: @"format"];
  if (fileTypeMenu)
  {
    NSString *extension = [[fileTypeMenu selectedItem] representedObject];
    if (![filename hasSuffix: extension])
      filename = [filename stringByAppendingPathExtension: extension];
  }
  return filename;  
}


static bool filechooser_create(mforms::FileChooser *self, mforms::Form *owner, mforms::FileChooserType type, bool show_hidden)
{
  MFFileChooserImpl *chooser = [[[MFFileChooserImpl alloc] initWithObject:self type:type showHidden: show_hidden] autorelease];
  chooser->mParent = owner;
  return true;
}


static void filechooser_set_title(mforms::FileChooser *self, const std::string &title)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    [chooser->mPanel setTitle: wrap_nsstring(title)];
  }
}


static bool filechooser_run_modal(mforms::FileChooser *self)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    NSString *filename = chooser->mDefaultFileName;
    
    if (chooser->mOptionsView)
      [chooser->mPanel setAccessoryView: chooser->mOptionsView];
    
    if (chooser->mParent && 0)
    {// XXX this is not working as expected, need a modal loop to block the call until the sheet is done
      [chooser->mPanel setMessage: [chooser->mPanel title]];
      [chooser->mPanel setDelegate: chooser];
      if (filename != nil)
        [chooser->mPanel setNameFieldStringValue: filename];
      __block bool retval = false;
      [chooser->mPanel beginSheetModalForWindow: chooser->mParent->get_data()
                              completionHandler: ^(NSInteger result) {
                                retval = result == NSFileHandlingPanelOKButton;
                              }];
      return retval;
    }
    else
    {
      [chooser->mPanel setMessage: @""];
      if (filename != nil)
        [chooser->mPanel setNameFieldStringValue: filename];
      if ([chooser->mPanel runModal] == NSFileHandlingPanelOKButton)
        return true;
    }
  }
  return false;
}

static void filechooser_set_directory(mforms::FileChooser *self, const std::string &path)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    [chooser->mPanel setDirectoryURL: [NSURL fileURLWithPath: wrap_nsstring(path) isDirectory: YES]];
  }
}


static std::string filechooser_get_directory(mforms::FileChooser *self)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    return [[chooser->mPanel.URL URLByDeletingLastPathComponent].path UTF8String];
  }
  return "";
}


static std::string filechooser_get_path(mforms::FileChooser *self)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
    return [chooser->mPanel.URL.path UTF8String];
  return "";
}


static void filechooser_set_path(mforms::FileChooser *self, const std::string &path)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    NSString *fpath = wrap_nsstring(path);

    NSString *extension = [fpath pathExtension];
    NSString *directory = [fpath stringByDeletingLastPathComponent];
    if (directory)
      [chooser->mPanel setDirectoryURL: [NSURL fileURLWithPath: directory isDirectory: YES]];
    chooser->mDefaultFileName = [[fpath lastPathComponent] retain];
    
    NSPopUpButton *popup = [chooser->mOptionControls objectForKey: @"format"];
    if (popup)
    {
      NSInteger i = [popup indexOfItemWithRepresentedObject: extension];
      if (i >= 0)
        [popup selectItemAtIndex: i];
    }
  }
}


static void filechooser_set_extensions(mforms::FileChooser *self, const std::string &extensions, const std::string &default_extension)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    NSMutableArray *array= [NSMutableArray array];
    NSMutableArray *fileTypes= [NSMutableArray array];

    // extensions format:
    // AAA Files (*.aaa)|*.aaa|BBB Files (*.bbb)|*.bbb
    
    std::vector<std::pair<std::string, std::string> > extlist= self->split_extensions(extensions);
    for (std::vector<std::pair<std::string, std::string> >::const_iterator iter= extlist.begin();
      iter != extlist.end(); ++iter)
    {
      [fileTypes addObject: wrap_nsstring(iter->first)];
      if (iter->second.size() > 2 || iter->second.substr(0, 2) == "*.")
        [array addObject: [NSString stringWithUTF8String: iter->second.substr(2).c_str()]];
      else if (iter->second[0] == '*')
        [array addObject: [NSString stringWithUTF8String: iter->second.substr(1).c_str()]];
      [fileTypes addObject: [array lastObject]];
    }

    if ([array count] > 0)
      [chooser->mPanel setAllowedFileTypes: array];
  }
}


static void filechooser_add_selector_option(mforms::FileChooser *self, const std::string &name, const std::string &label, const std::vector<std::pair<std::string, std::string> > &options)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    NSMutableArray *optlist = [NSMutableArray arrayWithCapacity: options.size()*2];
    for (std::vector<std::pair<std::string, std::string> >::const_iterator iter = options.begin();
         iter != options.end(); ++iter)
    {
      [optlist addObject: wrap_nsstring(iter->first)];
      [optlist addObject: wrap_nsstring(iter->second)];
    }
    id popupButton = [chooser addSelectorOption: optlist label: wrap_nsstring(label)];
    if (popupButton)
      [chooser->mOptionControls setObject: popupButton forKey: wrap_nsstring(name)];
  }
}


static std::string filechooser_get_selector_option_value(mforms::FileChooser *self, const std::string &name)
{
  MFFileChooserImpl *chooser= self->get_data();
  if (chooser)
  {
    if (name == "format")
      return [[[chooser->mOptionControls objectForKey: wrap_nsstring(name)] titleOfSelectedItem] UTF8String] ?: "";
    return [[[[chooser->mOptionControls objectForKey: wrap_nsstring(name)] selectedItem] representedObject] UTF8String] ?: "";
  }
  return "";
}


void cf_filechooser_init()
{
  ::mforms::ControlFactory *f = ::mforms::ControlFactory::get_instance();
  
  f->_filechooser_impl.create= &filechooser_create;
  f->_filechooser_impl.set_title= &filechooser_set_title;
  f->_filechooser_impl.set_directory= &filechooser_set_directory;
  f->_filechooser_impl.get_directory= &filechooser_get_directory;
  f->_filechooser_impl.get_path= &filechooser_get_path;
  f->_filechooser_impl.set_path= &filechooser_set_path;
  f->_filechooser_impl.run_modal= &filechooser_run_modal; 
  f->_filechooser_impl.set_extensions= &filechooser_set_extensions;
  f->_filechooser_impl.add_selector_option = &filechooser_add_selector_option;
  f->_filechooser_impl.get_selector_option_value = &filechooser_get_selector_option_value;
}


@end
