/*
SRTabView.m

Author: Makoto Kinoshita

Copyright 2004 The Shiira Project. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of 
  conditions and the following disclaimer in the documentation and/or other materials provided 
  with the distribution.

THIS SOFTWARE IS PROVIDED BY THE SHIIRA PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SHIIRA PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/

#import "SRDefaultsKey.h"

#import "SRTabView.h"
#import "HTSRTabBarView.h"

#import "WebKitEx.h"

//static const int    SRTabClipSegmentWidth = 20;
static const int    SRTagSegmentDummyDefaultHeight = 22;
static const int    SRTagSegmentMarginX = 0;

@interface SRTabView (private)
-(void)_addSelectedItemsOrder:(id)item;
@end

@implementation SRTabView

- (void)_updateSegment
{
	[[self tabBarView] _updateMatrixAndMenu];
   
    // Update appearance
    if (!_isTabShownAlways) {
        [self updateAppearance];
    }
}

#pragma mark -
//--------------------------------------------------------------//
// Initialize
//--------------------------------------------------------------//

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) {
        return nil;
    }
    
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Initialize instance variables
    _tabDefaultWidth = [defaults integerForKey:SRTabDefaultWidth];
    if (_tabDefaultWidth == 0) {
        _tabDefaultWidth = 180;
    }
    _tabMinWidth = [defaults integerForKey:SRTabMinWidth];
    if (_tabMinWidth == 0) {
        _tabMinWidth = 100;
    }
    _labels = [[NSMutableArray alloc]initWithCapacity:8];
    
    _selectedItemsOrder=[[NSMutableArray alloc]initWithCapacity:8];
    _isTabShownAlways = YES;
    _isTabShown = YES;
    _isSeparatorShown = YES;
    
    // Create components
    HTSRTabBarView* tabBarView;
    tabBarView = [[HTSRTabBarView alloc] 
            initWithFrame:NSMakeRect(
                    SRTagSegmentMarginX, 
                    frame.size.height, 
                    frame.size.width - SRTagSegmentMarginX, 
                    SRTagSegmentDummyDefaultHeight)];
    [tabBarView autorelease];
    [tabBarView setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
    [tabBarView setHasCloseButton:YES];
    [tabBarView setTabDefaultWidth:_tabDefaultWidth];
    [tabBarView setTabMinWidth:_tabMinWidth];
    [tabBarView setParentTabView:self];
    [self addSubview:tabBarView];
    
    NSTabView*  tabView;
    tabView = [[NSTabView alloc] 
            initWithFrame:NSMakeRect(
                    0, 0, frame.size.width, frame.size.height - [tabBarView frame].size.height)];
    [tabView autorelease];
    [tabView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
    [tabView setTabViewType:NSNoTabsNoBorder];
    [tabView setDelegate:self];
    [self addSubview:tabView];
    
    // Register key value observation
    [defaults addObserver:self 
            forKeyPath:SRTabDefaultWidth 
            options:NSKeyValueObservingOptionNew 
            context:NULL];
    [defaults addObserver:self 
            forKeyPath:SRTabMinWidth 
            options:NSKeyValueObservingOptionNew 
            context:NULL];
    [defaults addObserver:self 
            forKeyPath:SRTabStyleClassName 
            options:NSKeyValueObservingOptionNew 
            context:NULL];
    
    return self;
}

- (void)dealloc
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObserver:self forKeyPath:SRTabDefaultWidth];
    [defaults removeObserver:self forKeyPath:SRTabMinWidth];
    [defaults removeObserver:self forKeyPath:SRTabStyleClassName];
    
    [_labels release];
	[_selectedItemsOrder release];
    
    [[self tabBarView] setParentTabView:nil];
    [[self tabView] setDelegate:nil];
    
    [super dealloc];
}

//--------------------------------------------------------------//
// Working with tab items
//--------------------------------------------------------------//

- (void)addItemWithLabel:(NSString*)label view:(NSView*)view
{
	[self addItemWithLabel:label view:view select:NO];
}

- (void)addItemWithLabel:(NSString*)label view:(NSView*)view select:(BOOL)select
{
    NSTabView*  tabView;
    tabView = [self tabView];
    
	//save current selection
//	id  savedItem=[tabView selectedTabViewItem];

    // Add label to labels array
    [_labels addObject:label];
    
    // Create and add tab view item
    SRTabViewItem*  item;
    item = [[SRTabViewItem alloc] initWithIdentifier:nil];
    [item autorelease];
	[item setTabBarView:[self tabBarView]];  //SRTabViewItem method
	[item setLabel:label];
    [tabView addTabViewItem:item];
	[self _addSelectedItemsOrder:item];

    // Set view to tab view item
    [item setView:view];
    
#if 1
    // Select new tab
    if (select) {
        [tabView selectTabViewItem:item];
    }
#else
	//select if select==YES, or fake select for frame page
	[tabView selectTabViewItem:item];

	//restore current selection
	if(!select && savedItem)
		[tabView selectTabViewItem:savedItem];
#endif
    
    // Update segemnt
    [self _updateSegment];
}

- (void)removeItemAtIndex:(int)index
{
    NSTabView*  tabView;
    tabView = [self tabView];
    
	id      removeItem=[tabView tabViewItemAtIndex:index];
	BOOL	ajustSelection = NO;

	[_selectedItemsOrder removeObject:removeItem];

	if([tabView selectedTabViewItem]==removeItem){
		ajustSelection=YES;
	}
    [_labels removeObjectAtIndex:index];
    [tabView removeTabViewItem:removeItem];
	
	if(ajustSelection){
		id prevSelectedItem=nil;
        int tabSelectionLogic=[[NSUserDefaults standardUserDefaults] integerForKey:SRTabSelectionLogic];
        switch(tabSelectionLogic){
        case SRTabSelectionPreviousTab:{
            //Shiira type logic
            prevSelectedItem=[_selectedItemsOrder lastObject];
            break;
        }
        case SRTabSelectionRightTab:{
            //Safari type logic
            int count=[tabView numberOfTabViewItems];
            if(index < count){
                prevSelectedItem=[tabView tabViewItemAtIndex:index];
            }else{
                prevSelectedItem=nil;
            }
            break;
        }
        }
        
		if(prevSelectedItem){
            [tabView selectTabViewItem:prevSelectedItem];
        }
	}
    
    [self _updateSegment];
}

- (void)selectItemAtIndex:(int)index
{
    NSTabView*  tabView;
    tabView = [self tabView];
    
    [self _addSelectedItemsOrder:[tabView tabViewItemAtIndex:index]];
    [tabView selectTabViewItemAtIndex:index];
    
//    [self _updateSegment];
}

- (int)selectedIndex
{
    NSTabView*  tabView;
    tabView = [self tabView];
    
    // Get selected tab view item
    NSTabViewItem*  tabViewItem;
    tabViewItem = [tabView selectedTabViewItem];
    if (!tabViewItem) {
        return -1;
    }
    
    // Return index of selected item
    return [tabView indexOfTabViewItem:tabViewItem];
}

- (void)removeAllItems
{
    NSTabView*  tabView;
    tabView = [self tabView];
    
	[_selectedItemsOrder removeAllObjects];

	int i,cnt=[tabView numberOfTabViewItems];
	for(i=cnt-1;i>=0;i--){
		id  item=[tabView tabViewItemAtIndex:i];
		[tabView removeTabViewItem:item];
	}
}

- (NSTabView*)tabView
{
    NSEnumerator*   enumerator;
    id              view;
    enumerator = [[self subviews] objectEnumerator];
    while (view = [enumerator nextObject]) {
        if ([view isKindOfClass:[NSTabView class]]) {
            return view;
        }
    }
    
    return nil;
}

- (NSView*)viewOfSelectedTabViewItem
{
    // Get selected tab view item
    NSTabViewItem*  tabViewItem;
    tabViewItem = [[self tabView] selectedTabViewItem];
    if (!tabViewItem) {
        return nil;
    }
    
    // Return view of selected item
    return [tabViewItem view];
}

- (NSView*)viewAtIndex:(int)index
{
    // Get tab view item at index
    NSTabViewItem*  tabViewItem;
    tabViewItem = [[self tabView] tabViewItemAtIndex:index];
    if (!tabViewItem) {
        return nil;
    }
    
    // Return view of selected item
    return [tabViewItem view];
}

- (int)indexOfView:(NSView*)view
{
    // Check argument
    if (!view) {
        return -1;
    }
    
    // Get number of item
    int numberOfItems;
    numberOfItems = [[self tabView] numberOfTabViewItems];
    
    // Search view
    int i;
    for (i = 0; i < numberOfItems; i++) {
        // Check view
        if ([self viewAtIndex:i] == view) {
            return i;
        }
    }
    
    return -1;
}

- (NSString*)labelAtIndex:(int)index
{
    return [_labels objectAtIndex:index];
}

- (void)setLabel:(NSString*)label 
        atIndex:(int)index
{
    [_labels replaceObjectAtIndex:index withObject:label];
    id item=[[self tabView] tabViewItemAtIndex:index];
	[item setLabel:label];

    [self _updateSegment];
}

- (int)numberOfItems
{
    // Return nubmer of tab view item
    return [[self tabView] numberOfTabViewItems];
}

-(void)_addSelectedItemsOrder:(id)item;
{
	[_selectedItemsOrder removeObject:item];
	[_selectedItemsOrder addObject:item];
}
//--------------------------------------------------------------//
// Actions
//--------------------------------------------------------------//

- (void)setFrame:(NSRect)frame
{
    [super setFrame:frame];
}

- (HTSRTabBarView*)tabBarView
{
    NSEnumerator*   enumerator;
    id              view;
    enumerator = [[self subviews] objectEnumerator];
    while (view = [enumerator nextObject]) {
        if ([view isKindOfClass:[HTSRTabBarView class]]) {
            return view;
        }
    }
    
    return nil;
}

#pragma mark -
//--------------------------------------------------------------//
// Tab appearance
//--------------------------------------------------------------//

- (void)updateAppearance
{
    // Check availablity of tab shown
    BOOL    isTabShown;
    isTabShown = _isTabShown && (_isTabShownAlways || [self numberOfItems] > 1);
	
    // Get frame size
    NSRect  frame, tabViewFrame;
    frame = [self frame];
    tabViewFrame = [[self tabView] frame];
    
    // Calculate differences with contents frame and tab view frame
    /*static*/ float  _diff = -1;
    if (_diff == -1) {
		_diff = [[self tabBarView] frame].size.height;
    }
    
    int tabFrameHeight = tabViewFrame.size.height;
    if (isTabShown) {
        tabFrameHeight = frame.size.height - _diff;
    }else{
        if (_isSeparatorShown) {
            tabFrameHeight = frame.size.height - 1;
        }else{
            tabFrameHeight = frame.size.height;
        }
    }
    
    if (tabViewFrame.size.height != tabFrameHeight) {
        tabViewFrame.size.height = tabFrameHeight;
        [[self tabView] setFrame:tabViewFrame];
    }
    [[self tabBarView] setHidden:!isTabShown];
    
    [self setNeedsDisplay:YES];
}


- (void)drawRect:(NSRect)rect {
    float x=rect.origin.x;
    float y=rect.origin.y;
	if ([[self tabBarView] isHidden] /* && _isSeparatorShown*/) {
		NSColor*	lineColor;
		if([[self window]styleMask]&NSTexturedBackgroundWindowMask){
			lineColor=[NSColor darkGrayColor];
		}else{
			lineColor=[NSColor controlShadowColor];
		}

		[lineColor set];
		[NSBezierPath strokeLineFromPoint:NSMakePoint(x,y+rect.size.height-0.5) toPoint:NSMakePoint(x+rect.size.width,y+rect.size.height-0.5)];
		return;
	}
	else [super drawRect:rect];
}

- (BOOL)isTabShown
{
    return _isTabShown;
}

- (void)setTabShown:(BOOL)shown
{
    if (_isTabShown != shown) {
        _isTabShown = shown;
        
        [self updateAppearance];
    }
}

- (BOOL)isTabShownAlways
{
    return _isTabShownAlways;
}

- (void)setTabShownAlways:(BOOL)shown
{
    if (_isTabShownAlways != shown) {
        _isTabShownAlways = shown;
        
        [self updateAppearance];
    }
}

- (BOOL)isSeparatorShown
{
    return _isSeparatorShown;
}

- (void)setSeparatorShow:(BOOL)shown
{
    if (_isSeparatorShown != shown) {
        _isSeparatorShown = shown;
        
        [self updateAppearance];
    }
}


- (BOOL)isAccordingToStringWidth
{
    return [[self tabBarView] accordingToLabelWidth];
}

- (void)setAccordingToStringWidth:(BOOL)flag
{
    [[self tabBarView] setAccordingToLabelWidth:flag];
}


#pragma mark -
//--------------------------------------------------------------//
// Delegate
//--------------------------------------------------------------//

- (id)delegate
{
    return _delegate;
}

- (void)setDelegate:(id)delegate
{
    _delegate = delegate;
}

//--------------------------------------------------------------//
// NSTabView delegate
//--------------------------------------------------------------//

- (BOOL)tabView:(NSTabView*)tabView 
        shouldSelectTabViewItem:(NSTabViewItem*)tabViewItem
{
    if ([_delegate respondsToSelector:@selector(srTabView:shouldSelectTabViewItem:)]) {
        // Notify to delegate
        return [_delegate srTabView:self shouldSelectTabViewItem:(SRTabViewItem*)tabViewItem];
    }
    
    return YES;
}

- (void)tabView:(NSTabView*)tabView 
        willSelectTabViewItem:(NSTabViewItem*)tabViewItem
{
    if ([_delegate respondsToSelector:@selector(srTabView:willSelectTabViewItem:)]) {
        // Notify to delegate
        [_delegate srTabView:self willSelectTabViewItem:(SRTabViewItem*)tabViewItem];
    }
}

- (void)tabView:(NSTabView*)tabView 
        didSelectTabViewItem:(NSTabViewItem*)tabViewItem
{
	[[self tabBarView] tabView:tabView didSelectTabViewItem:tabViewItem];
    
	if ([_delegate respondsToSelector:@selector(srTabView:didSelectTabViewItem:)]) {
        // Notify to delegate
        [_delegate srTabView:self didSelectTabViewItem:(SRTabViewItem*)tabViewItem];
    }
}

- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView*)tabView
{
    if ([_delegate respondsToSelector:@selector(srTabViewDidChangeNumberOfTabViewItems:)]) {
        // Notify to delegate
        [_delegate srTabViewDidChangeNumberOfTabViewItems:self];
    }
}

#pragma mark -
//ignored key action
- (void)keyDown:(NSEvent *)theEvent
{
	BOOL	ignored=YES;
	unsigned int	mod=[theEvent modifierFlags];
	unsigned short  key=[theEvent keyCode];
/*
	BOOL	cmdDown=(mod & NSCommandKeyMask)==NSCommandKeyMask;
	BOOL	ctlDown=(mod & NSControlKeyMask)==NSControlKeyMask;
	BOOL	optDown=(mod & NSAlternateKeyMask)==NSAlternateKeyMask;

	if(cmdDown||ctlDown||optDown){
*/	if(mod & (NSCommandKeyMask|NSControlKeyMask|NSAlternateKeyMask)){
		ignored=YES;
	}else if(key==0x2B ||key==0x5F){  //,
		[NSApp sendAction:@selector(previousTabAction:) to:nil from:self];
		ignored=NO;
	}else if(key==0x2F ||key==0x41){  //.
		[NSApp sendAction:@selector(nextTabAction:) to:nil from:self];
		ignored=NO;
	}
	
	if(ignored) [[self nextResponder]keyDown:theEvent];
}



#pragma mark -
//--------------------------------------------------------------//
// Key value observation
//--------------------------------------------------------------//

- (void)observeValueForKeyPath:(NSString*)keyPath 
        ofObject:(id)object 
        change:(NSDictionary*)change 
        context:(void *)context
{
    // Tab preferences
    if ([keyPath isEqualToString:SRTabDefaultWidth]) {
        // Set tab default width
        _tabDefaultWidth = [object integerForKey:SRTabDefaultWidth];
        if (_tabDefaultWidth == 0) {
            _tabDefaultWidth = 180;
        }
        [[self tabBarView] setTabDefaultWidth:_tabDefaultWidth];
        // Update segment
        [self _updateSegment];
        return;
    }
    if ([keyPath isEqualToString:SRTabMinWidth]) {
        // Set tab minimum width
        _tabMinWidth = [object integerForKey:SRTabMinWidth];
        if (_tabMinWidth == 0) {
            _tabMinWidth = 100;
        }
        
        [[self tabBarView] setTabMinWidth:_tabMinWidth];
        // Update segment
        [self _updateSegment];
        return;
    }
    if ([keyPath isEqualToString:SRTabStyleClassName]) {
		[[self tabBarView] setCellClassWithName:[object stringForKey:SRTabStyleClassName]];
	}
}

@end

#pragma mark -

@implementation SRTabViewItem

- (id)initWithIdentifier:(id)identifier
{
    self = [super initWithIdentifier:identifier];
    if (self) {
		_isLoading=NO;
	}
	return self;
}

- (void)dealloc
{
	WebView* webView;
    webView = [self view];
	if ([webView respondsToSelector:@selector(setHostWindow:)]) {
		[webView setHostWindow:nil];
		//kokono dealloc ga SRMainWindowController dealloc yori ato ni natteshimatteru node
		[webView setFrameLoadDelegate:nil];
		[webView setResourceLoadDelegate:nil];
		[webView setPolicyDelegate:nil];
		[webView setUIDelegate:nil];
		[webView setDownloadDelegate:nil];
        
        // Stop loading
        [webView stopLoading:self];
        
        // Close web view
        // I'm not sure I need to call it...
        [webView _close];
	}
	[self setView:nil];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    [_userInfo release];
    
	[super dealloc];
}

- (void)setView:(NSView *)view
{
	[super setView:view];

	if([view isKindOfClass:[WebView class]]){
		// Register notifications
		NSNotificationCenter*   center;
		center = [NSNotificationCenter defaultCenter];

		[center addObserver:self
				selector:@selector(noteFromWebView:)
				name:WebViewProgressFinishedNotification object:view];
		[center addObserver:self 
				selector:@selector(noteFromWebView:) 
				name:WebViewProgressStartedNotification 
				object:view];
		[center addObserver:self 
				selector:@selector(noteFromWebView:) 
				name:WebViewProgressEstimateChangedNotification 
				object:view];
	}
}

#pragma mark -
- (void)setTabBarView:(HTSRTabBarView*)view
{
	_keeperView=view;
}

- (void)setIsLoading:(BOOL)flag
{
	_isLoading=flag;
}
- (BOOL)isLoading
{
	return _isLoading;
}

//Notification from WebView
-(void)noteFromWebView:(NSNotification*)notification
{
	if(!_keeperView) return;
	int idx=[[self tabView]indexOfTabViewItem:self];
	
	NSString*   name=[notification name];
	if([name isEqualToString:WebViewProgressStartedNotification]){
		_isLoading=YES;
		[_keeperView tabViewItemStartedLoading:idx];
	}else if([name isEqualToString:WebViewProgressFinishedNotification]){
		_isLoading=NO;
		[_keeperView tabViewItemFinishedLoading:idx];
	}else if([name isEqualToString:WebViewProgressEstimateChangedNotification]){
		[_keeperView tabViewItemEstimateChanged:idx progress:[[notification object] estimatedProgress]];
	}
}

- (id)userInfo
{
    return _userInfo;
}

- (void)setUserInfo:(id)userInfo
{
    if (userInfo != _userInfo) {
        [_userInfo release];
        _userInfo = [userInfo retain];
    }
}

@end