// ServerDelegate.mm: OVDisplayServer.app delegated object
//
// Copyright (c) 2004-2006 The OpenVanilla Project (http://openvanilla.org)
// 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.
// 3. Neither the name of OpenVanilla nor the names of its contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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 "ServerDelegate.h"
#import "NSDictionaryExtension.h"
#import "NSStringExtension.h"
#import <Carbon/Carbon.h>
#import <WebKit/WebKit.h>

#define CVIB_FADEWAIT       0.5     // fade after 0.5 sec
#define CVIB_FADEINTERVAL   0.05    // 0.05 sec/frame
#define CVIB_FADEVALUE      0.025   // alphaValue-=0.025/frame

enum {
    OVDPS_NOTIFY_DEFAULT=0,
    OVDPS_NOTIFY_SILENT=1
};

enum {
    OVDPS_CANDI_MAYHIDE=0,
    OVDPS_CANDI_ALWAYSSHOW=1
};

enum {
    OVDPS_CANDI_MAYMOVE=0,
    OVDPS_CANDI_FIXED=1
};

void CVFixWindowOrigin(NSWindow *w, Point p);

#define CVWS_DEFAULTFILE	@"~/Sites/ov-theme/ov.html"

@protocol OVKeyReceiver
- (void)sendKey:(char)c;
@end

@implementation ServerDelegate
- (IBAction)sendKeyTest:(id)sender {
	NSLog(@"getting remote object");
	id keyrcvr=[[NSConnection rootProxyForConnectionWithRegisteredName:@"OVKeyReceiverTest" host:nil] retain];
	if (keyrcvr) {
		NSLog(@"setting protocol");
		[keyrcvr setProtocolForProxy:@protocol(OVKeyReceiver)];
		
		NSLog(@"sending keys");
		[keyrcvr sendKey:'e'];
		[keyrcvr sendKey:' '];
		[keyrcvr sendKey:'2'];
		NSLog(@"releasing remote object");
		[keyrcvr release];
		NSLog(@"session ended");
	}
	else {
		NSLog(@"cannot connect to remote object");
	}
}

- (void)awakeFromNib {
	NSLog(@"WebkitServer started");
	NSConnection *c=[NSConnection defaultConnection];
	[c setRootObject:self];
    if ([c registerName:OVDSPSRVR_NAME]) ; // NSLog(@"OVDisplayServer registered");
	else {
		NSLog(@"WebkitServer registration failed");
		NSAlert *a=[NSAlert alertWithMessageText:@"WebKitServer registration failed!"
			defaultButton:nil
			alternateButton:nil
			otherButton:nil
			informativeTextWithFormat:@"Make sure you have killed the process of OVDisplayServer"];
		[a runModal];
		[[NSApplication sharedApplication] terminate:self];
	}

	candion=NO;
	fadetimer=nil;

	NSLog([urlbase absoluteString]);
	
	NSString *toload=[CVWS_DEFAULTFILE stringByExpandingTildeInPath];
	NSLog(@"this default candidate html file will be used: %@", toload);
	
	NSURL *loadurl=[NSURL fileURLWithPath:toload];
	NSLog([loadurl description]);
		
	[[candiweb mainFrame] loadRequest:[NSURLRequest requestWithURL:loadurl]];
	[candiweb setUIDelegate:self];
    [candiweb setFrameLoadDelegate:self];
	[candiweb setEditable:NO];

	[candi setHasShadow:YES];
    [candiweb setDrawsBackground:NO];
	if(candialwaysshow != OVDPS_CANDI_ALWAYSSHOW) {
		[candi orderOut:self];
	}
}
- (void)setConfig:(NSDictionary*)cfg {
	
	notialpha=[noti alphaValue];

    notistyle=OVDPS_NOTIFY_DEFAULT; 
    NSString *ns=[cfg valueForKey:@"notificationStyle" default:@"default"];
    if ([ns isEqualToString:@"silent"]) notistyle=OVDPS_NOTIFY_SILENT;
	
	candialwaysshow = OVDPS_CANDI_MAYHIDE;
	NSString *ns2=[cfg valueForKey:@"candialwaysshow" default:@"false"];
    if ([ns2 isEqualToString:@"true"]) candialwaysshow=OVDPS_CANDI_ALWAYSSHOW;
	else [cfg setValue:@"false" forKey:@"candialwaysshow"];
	
	candifix = OVDPS_CANDI_MAYMOVE;
	NSString *ns3=[cfg valueForKey:@"candifix" default:@"false"];
    if ([ns3 isEqualToString:@"true"]) candifix= OVDPS_CANDI_FIXED;	
	else [cfg setValue:@"false" forKey:@"candifix"];
}
- (void)candidateShow {
	candion=YES;
	[self solveConflict];
	[candi orderFront:self];
    // nop();
}
- (void)candidateHide {
	candion=NO;

	NSLog(@"clear");
	
	WebScriptObject *scrobj = [candiweb windowScriptObject];
	
	NSString *script=[NSString stringWithFormat:@"ov_clear()"];
	NSLog(@"evaluating javascript: %@", script);
	id y=[scrobj evaluateWebScript:script];
	if (y) {
		NSLog(@"cleared!!!!", [y description]);
	}	
	
	if(candialwaysshow != OVDPS_CANDI_ALWAYSSHOW) {
		[candi orderOut:self];
	}
}
- (void)candidateUpdate:(bycopy NSString*)s position:(Point)p {
	NSLog(@"candiupdate");

	WebScriptObject *scrobj = [candiweb windowScriptObject];
	
	NSString *script=[NSString stringWithFormat:@"ov_update('%@')", s];
	NSLog(@"evaluating javascript: %@", script);
	id y=[scrobj evaluateWebScript:script];
	if (y) {
	   NSLog(@"update text!!!!", [y description]);
	}


	if(candifix != OVDPS_CANDI_FIXED) {
		CVFixWindowOrigin(candi, p);
	}
}
- (void)notifyMessage:(bycopy NSString*)s position:(Point)p {
	NSLog(@"notiupdate");
	
	WebScriptObject *scrobj = [candiweb windowScriptObject];
	
	NSString *script=[NSString stringWithFormat:@"ov_notify('%@')", s];
	NSLog(@"evaluating javascript: %@", script);
	id y=[scrobj evaluateWebScript:script];
	if (y) {
		NSLog(@"update text!!!!", [y description]);
	}	
	
	[candi orderFront:self];
	if(candifix != OVDPS_CANDI_FIXED) {
		CVFixWindowOrigin(candi, p);
	}	

//	CVFixWindowOrigin(noti, p);
//	[self solveConflict];
    
//    if (notistyle!=OVDPS_NOTIFY_DEFAULT) return;
//    [noti orderFront:self];
}
- (void)notifyClose {
	[noti orderOut:self];
}
- (void)notifyFade {
    if (fadetimer) [self stopTimer];
    
    if (notistyle!=OVDPS_NOTIFY_DEFAULT) return;
    fadetimer=[NSTimer scheduledTimerWithTimeInterval:CVIB_FADEWAIT target:self selector:@selector(fadeStart) userInfo:nil repeats:NO];
}
- (void)aboutDialog {
    // [aboutdialog setLevel:NSScreenSaverWindowLevel];
    // [aboutdialog orderFront:self];
	[[NSApplication sharedApplication] orderFrontStandardAboutPanel:self];
}
- (void)dealloc {
    [defaultbackground release];
	[urlbase release];
	[super dealloc];
}
- (void)stopTimer {
    if (fadetimer) [fadetimer invalidate];
    fadetimer=nil;
	[noti setAlphaValue:notialpha];
}
- (void)fadeStart {
    [fadetimer invalidate];
    fadetimer=[NSTimer scheduledTimerWithTimeInterval:CVIB_FADEINTERVAL target:self selector:@selector(fadeWork) userInfo:nil repeats:YES];
    fadealpha=notialpha;
}
- (void)fadeWork {
    fadealpha-=CVIB_FADEVALUE;
    if (fadealpha<=0) {
        [noti orderOut:self];
        [self stopTimer];
        // nop();
        return;
    }
	[noti setAlphaValue:fadealpha];

}
- (void)solveConflict {
	if (!candion) return;
	NSRect cfr, nfr;
	cfr=[candi frame];
	nfr=[noti frame];
	if (cfr.origin.y+cfr.size.height == nfr.origin.y+nfr.size.height) {
		nfr.origin.y = cfr.origin.y - (nfr.size.height + 5);
		[noti setFrameOrigin:nfr.origin];
	}
}

@end

void CVFixWindowOrigin(NSWindow *w, Point p) {
	// first of all, we do a y-coordiate transformation (mirroring)
	NSPoint np=NSMakePoint((float)p.h, (float)p.v);
	
	float maxh=480;		// a silly default, but anyway the below loop always runs
	NSArray *sa=[NSScreen screens];
	int i, c=[sa count];
	for (i=0; i<c; i++) {
		float h=[[sa objectAtIndex:i] frame].size.height;
		if (h > maxh) maxh=h;
	}
	
	np.y=maxh-np.y;

	NSSize s=[w frame].size;
	
	// now we determine the window frame
	NSRect f=[[NSScreen mainScreen] frame];
	BOOL found=NO;

	for (i=0; i<c; i++) {
		NSRect sf=[[sa objectAtIndex:i] frame];
		if (NSPointInRect(np, sf)) {
			f=sf;
			found=YES;
		}
	}

	// if the origin is out of bound, we place the origin in the center of the main screen
	if (found) {
		np.y-=s.height;		// must offset the height of the window
		if (np.y > f.origin.y+f.size.height-s.height) np.y=f.origin.y+f.size.height-s.height;
		if (np.x > f.origin.x+f.size.width-s.width) np.x=f.origin.x+f.size.width-s.width;
		if (np.y < f.origin.y) np.y=f.origin.y;
		if (np.x < f.origin.x) np.x=f.origin.x;
	}
	else {
		np.x = f.origin.x + (f.size.width-s.width)/2;
		np.y = f.origin.y + (f.size.height-s.height)/2;
	}
	
	[w setFrameOrigin:np];
}
