//
//  KeyEquivView.m
//  Afficheur
//
//  Created by kichi on 08/04/10.
//  Copyright 2008 Katsuhiko Ichinose. All rights reserved.
//

#import "KeyEquivView.h"
#import "KeyEquivField.h"
#import "KeyEquivCell.h"


@implementation KeyEquivView

+ (UInt16)keyCodeForKeyCode:(UInt32)keyCode
{
	return keyCode & 0xff;
}

+ (UInt32)modifierKeyForKeyCode:(UInt32)keyCode
{
	return keyCode & (NSShiftKeyMask | NSAlternateKeyMask | NSControlKeyMask | NSCommandKeyMask);
}

- (id)init
{
	self = [super init];
	if (self)
	{
		[self setFieldEditor:YES];
		_keyCode = (UInt32)-1;
		_textField = nil;
		_enableKeyDown = NO;
		_cancelButton = [[NSImage imageNamed:@"Cancel"] retain];
		_cancelPush = [[NSImage imageNamed:@"CancelB"] retain];
		_functionKeys = [[NSDictionary dictionaryWithObjectsAndKeys:
						  @"Space",		@"31",
						  @"Prior",		@"21",
						  @"Next",		@"22",
						  @"PageUp",	@"74",
						  @"PageDown",	@"79",
						  @"End",		@"77",
						  @"Home",		@"73",
						  @"Left",		@"7B",
						  @"Up",		@"7E",
						  @"Right",		@"7C",
						  @"Down",		@"7D",
						  @"Delete⌦",	@"75",
						  @"Delete⌫",	@"33",
						  @"Help",		@"72",
						  @"F1",		@"7A",
						  @"F2",		@"78",
						  @"F3",		@"63",
						  @"F4",		@"76",
						  @"F5",		@"60",
						  @"F6",		@"61",
						  @"F7",		@"62",
						  @"F8",		@"64",
						  @"F9",		@"65",
						  @"F10",		@"6D",
						  @"F11",		@"67",
						  @"F12",		@"6F",
						  @"F13",		@"69",
						  @"F14",		@"6B",
						  @"F15",		@"71",
						  nil] retain];
		_padKeys = [[NSArray arrayWithObjects:
					 @"41",
					 @"43",
					 @"45",
					 @"4B",
					 @"4E",
					 @"51",
					 @"52",
					 @"53",
					 @"54",
					 @"55",
					 @"56",
					 @"57",
					 @"58",
					 @"59",
					 @"5B",
					 @"5C",
					 nil] retain];
		OSStatus err = KLGetCurrentKeyboardLayout(&_keyboardLayout);
		if (err != noErr)
		{
			return nil;
		}
		err = KLGetKeyboardLayoutProperty(_keyboardLayout, kKLKind, (const void **)&_keyLayoutKind);
		if (err != noErr)
		{
			return nil;
		}
		if (_keyLayoutKind == kKLKCHRKind)
		{
			err = KLGetKeyboardLayoutProperty(_keyboardLayout, kKLKCHRData, (const void **)&_KCHRData);
		}
		else
		{
			err = KLGetKeyboardLayoutProperty(_keyboardLayout, kKLuchrData, (const void **)&_uchrData);
		}
		if (err != noErr)
		{
			return nil;
		}
	}
	return self;
}

- (void)dealloc
{
	[_functionKeys release];
	[_padKeys release];
	[_cancelButton release];
	[_cancelPush release];
	[super dealloc];
}

- (BOOL)acceptsFirstResponder
{
	return YES;
}

- (NSString *)description
{
    NSString *kind;
    if (_keyLayoutKind == kKLKCHRKind)
	{
        kind = @"KCHR";
	}
    else
	{
        kind = @"uchr";
	}
    NSString *layoutName;
    KLGetKeyboardLayoutProperty(_keyboardLayout, kKLLocalizedName, (const void **)&layoutName);
    return [NSString stringWithFormat:@"%@ layout=%@ (%@)", [self className], layoutName, kind];
}

- (void)setTextField:(KeyEquivField *)textField
{
	_textField = textField;
	[self setInsertionPointColor:[self backgroundColor]];
	[_textField setTextView:self];
}

- (UInt32)keyCode
{
	return _keyCode;
}

- (BOOL)isValidKeyCode
{
	return (_keyCode != (UInt32)-1);
}

- (NSString *)translateKeyCode:(unsigned short)keyCode
			   withModifierKey:(unsigned int)modifierKey
{
    if (_keyLayoutKind == kKLKCHRKind)
	{
        UInt32 charCode = KeyTranslate( _KCHRData, keyCode, &_keyTranslateState );
        char theChar = (charCode & 0x00FF);
		return [[[NSString alloc] initWithData:[NSData dataWithBytes:&theChar length:1] encoding:NSMacOSRomanStringEncoding] autorelease];
    }
	UniCharCount maxStringLength = 10, actualStringLength;
	UniChar unicodeString[10];
	UCKeyTranslate(_uchrData, keyCode, kUCKeyActionDisplay, modifierKey, LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &_deadKeyState, maxStringLength, &actualStringLength, unicodeString);
	return [NSString stringWithCharacters:unicodeString length:actualStringLength];
}

- (NSString *)translateKeyCode:(unsigned short)keyCode
{
	return [self translateKeyCode:keyCode withModifierKey:0];
}

- (NSString *)stringForKeyCode:(unsigned short)keyCode
			   withModifierKey:(unsigned int)modifierKey
{
	NSString *keyStr = [NSString stringWithFormat:@"%02X", keyCode];
	NSString *result = [_functionKeys objectForKey:keyStr];
	if (!result)
	{
		result = [[self translateKeyCode:keyCode] uppercaseString];
		if ([_padKeys indexOfObject:keyStr] != NSNotFound)
		{
			result = [NSString stringWithFormat:@"Pad %@", result];
		}
	}
	//^⎇⇧⌘
	if (modifierKey & NSCommandKeyMask)
	{
		result = [NSString stringWithFormat:@"⌘%@", result];
	}
	if (modifierKey & NSShiftKeyMask)
	{
		result = [NSString stringWithFormat:@"⇧%@", result];
	}
	if (modifierKey & NSAlternateKeyMask)
	{
		result = [NSString stringWithFormat:@"⎇%@", result];
	}
	if (modifierKey & NSControlKeyMask)
	{
		result = [NSString stringWithFormat:@"^%@", result];
	}
	return result;
}

- (NSString *)stringForKeyCode:(unsigned short)keyCode
{
	return [self stringForKeyCode:keyCode withModifierKey:0];
}

- (void)setKeyCode:(UInt32)keyCode
{
	NSString *str = nil;
	_keyCode = keyCode;
	_enableKeyDown = NO;
	if (_keyCode != (UInt32)-1)
	{
		str = [self stringForKeyCode:[KeyEquivView keyCodeForKeyCode:_keyCode]
					 withModifierKey:[KeyEquivView modifierKeyForKeyCode:_keyCode]];
	}
	if ([[_textField cell] isKindOfClass:[KeyEquivCell class]])
	{
		[[_textField cell] setString:str];
		if (_keyCode == (UInt32)-1)
		{
			[[_textField cell] setImage:nil];
			[[_textField cell] setPlaceholderString:@"Click to Record"];
		}
		else
		{
			[[_textField cell] setImage:_cancelButton];
		}
		[_textField drawCell:[_textField cell]];
	}
	[self setString:@""];
}

- (void)setKeyCode:(UInt16)keyCode
   withModifierKey:(UInt32)modifierKey
{
	[self setKeyCode:(modifierKey & (NSShiftKeyMask |
									 NSAlternateKeyMask |
									 NSControlKeyMask |
									 NSCommandKeyMask)) | (UInt32)(keyCode & 0xff)];
}

- (void)setEnableKeyDown:(BOOL)enable
{
	_enableKeyDown = enable;
	if (![self isValidKeyCode])
	{
		if (_textField)
		{
			KeyEquivCell *cell = [_textField cell];
			if (cell && [cell isKindOfClass:[KeyEquivCell class]])
			{
				if (_enableKeyDown)
				{
					[[_textField cell] setPlaceholderString:@"Enter Hot key"];
				}
				else
				{
					[[_textField cell] setPlaceholderString:@"Click to Record"];
				}
				[_textField drawCell:[_textField cell]];
			}
		}
	}
}

- (BOOL)isEnableKeyDown
{
	return _enableKeyDown;
}

- (void)setCancelButton
{
	if (_textField)
	{
		KeyEquivCell *cell = [_textField cell];
		if (cell && [cell isKindOfClass:[KeyEquivCell class]])
		{
			[cell setImage:_cancelButton];
			[_textField drawCell:[_textField cell]];
		}
	}
}

- (void)setPushedCancelButton
{
	if (_textField)
	{
		KeyEquivCell *cell = [_textField cell];
		if (cell && [cell isKindOfClass:[KeyEquivCell class]])
		{
			[cell setImage:_cancelPush];
			[_textField drawCell:[_textField cell]];
		}
	}
}

- (BOOL)isCancelButton
{
	if (_textField)
	{
		KeyEquivCell *cell = [_textField cell];
		if (cell && [cell isKindOfClass:[KeyEquivCell class]])
		{
			//LOG(@"[%@ isCancelButton] %d", [self className], [[cell image] isEqual:_cancelButton]);
			return [[cell image] isEqual:_cancelButton];
		}
	}
	//LOG(@"[%@ isCancelButton] NO", [self className]);
	return NO;
}

- (BOOL)isPushedCancelButton
{
	if (_textField)
	{
		KeyEquivCell *cell = [_textField cell];
		if (cell && [cell isKindOfClass:[KeyEquivCell class]])
		{
			//LOG(@"[%@ isPushedCancelButton] %d", [self className], [[cell image] isEqual:_cancelPush]);
			return [[cell image] isEqual:_cancelPush];
		}
	}
	//LOG(@"[%@ isPushedCancelButton] NO", [self className]);
	return NO;
}

- (BOOL)becomeFirstResponder
{
	//LOG(@"[%@ becomeFirstResponder] %p", [self className], self);
	if (_textField && [_textField isLeopard])
	{
		return YES;
	}
	return [super becomeFirstResponder];
}

- (BOOL)resignFirstResponder
{
	//LOG(@"[%@ resignFirstResponder] %p", [self className], self);
	[self setEnableKeyDown:NO];
	return [super resignFirstResponder];
}

- (void)keyDown:(NSEvent *)theEvent
{
	LOG(@"[%@ keyDown]\n%@", [self className], theEvent);
	if (_enableKeyDown)
	{
		switch ([theEvent keyCode])
		{
			case 0x24:
			case 0x35:
			case 0x30:
				if ([self window])
				{
					if ([[[self window] firstResponder] isEqualTo:self])
					{
						LOG(@"[%@ keyDown] super", [self className]);
						[super keyDown:theEvent];
					}
				}
				if (_textField)
				{
					[_textField setEventDone:NO];
				}
				break;
			default:
				[self setKeyCode:[theEvent keyCode]
				 withModifierKey:[theEvent modifierFlags]];
				if (_textField)
				{
					[_textField setEventDone:YES];
				}
				break;
		}
	}
	else if ([self window])
	{
		if ([[[self window] firstResponder] isEqualTo:self])
		{
			LOG(@"[%@ keyDown] super", [self className]);
			[super keyDown:theEvent];
		}
	}
}

- (void)drawRect:(NSRect)dirtyRect
{	// Tigerでは、このMethodを無効にしないとフォーカスがあるときに上書きされてしまう
	//LOG(@"[%@ drawRect] %p", [self className], self);
	if (_textField && [_textField isLeopard])
	{
		[super drawRect:dirtyRect];
	}
}

- (BOOL)shouldDrawInsertionPoint
{
	return NO;
}

- (void)addCursorRect:(NSRect)aRect
			   cursor:(NSCursor *)aCursor
{
	//LOG(@"[%@ addCursorRect]\n%@: %f, %f - %f, %f",
	//	[self className], aCursor,
	//	aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
	if ([aCursor isEqualTo:[NSCursor IBeamCursor]])
	{
		aCursor = [NSCursor arrowCursor];
	}
	[super addCursorRect:aRect cursor:aCursor];
}

- (void)resetCursorRects
{
	//LOG(@"[%@ resetCursorRects]", [self className]);
	[self setAllowsUndo:NO];
	[self discardCursorRects];
	[self addCursorRect:[self bounds] cursor:[NSCursor arrowCursor]];
	if (_textField)
	{
		NSWindow *window = [_textField window];
		if (window)
		{
			[window invalidateCursorRectsForView:self];
		}
	}
}

- (void)setSelectedRange:(NSRange)charRange
{
	//LOG(@"[%@ setSelectedRange] %d, %d", [self className], charRange.location, charRange.length);
}

- (NSMenu *)menuForEvent:(NSEvent *)theEvent
{
	//LOG(@"[%@ menuForEvent]", [self className]);
	return nil;
}

- (void)cut:(id)sender
{
	//LOG(@"[%@ cut]", [self className]);
}

- (void)copy:(id)sender
{
	//LOG(@"[%@ copy]", [self className]);
}

- (void)paste:(id)sender
{
	//LOG(@"[%@ paste]", [self className]);
}

- (void)delete:(id)sender
{
	//LOG(@"[%@ delete]", [self className]);
}

- (void)mouseDown:(NSEvent *)theEvent
{
	//LOG(@"[%@ mouseDown]\n%@", [self className], theEvent);
	if (_textField)
	{
		[_textField mouseDown:theEvent];
	}
}

- (void)mouseDragged:(NSEvent *)theEvent
{
	//LOG(@"[%@ mouseDragged]", [self className]);
}

- (void)mouseUp:(NSEvent *)theEvent
{
	//LOG(@"[%@ mouseUp]\n%@", [self className], theEvent);
	if (_textField)
	{
		[_textField mouseUp:theEvent];
	}
}

- (void)mouseEntered:(NSEvent *)theEvent
{
	//LOG(@"[%@ mouseEntered]", [self className]);
}

- (void)mouseExited:(NSEvent *)theEvent
{
	//LOG(@"[%@ mouseExited]", [self className]);
}

- (void)mouseMoved:(NSEvent *)theEvent
{
	//LOG(@"[%@ mouseMoved]", [self className]);
}

- (void)rightMouseDown:(NSEvent *)theEvent
{
	//LOG(@"[%@ rightMouseDown]\n%@", [self className], theEvent);
}

- (void)rightMouseDragger:(NSEvent *)theEvent
{
	//LOG(@"[%@ rightMouseDragger]", [self className]);
}

- (void)rightMouseUp:(NSEvent *)theEvent
{
	//LOG(@"[%@ rightMouseUp]\n%@", [self className], theEvent);
}

- (void)otherMouseDown:(NSEvent *)theEvent
{
	//LOG(@"[%@ otherMouseDown]\n%@", [self className], theEvent);
}

- (void)otherMouseDragger:(NSEvent *)theEvent
{
	//LOG(@"[%@ otherMouseDragger]", [self className]);
}

- (void)otherMouseUp:(NSEvent *)theEvent
{
	//LOG(@"[%@ otherMouseUp]\n%@", [self className], theEvent);
}

@end
