/***************************************************************************
 *   Copyright (C) by Fabrizio Montesi                                     *
 *                                                                         *
 *   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; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                         *
 *   For details about the authors of this software, see the AUTHORS file. *
 ***************************************************************************/


package com.italianasoftware.echoes.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.WindowCloseListener;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import joliex.gwt.client.JolieService;
import joliex.gwt.client.Value;

public class Echoes implements EntryPoint
{
	private TextBox location = new TextBox();
	private Label cpLabel = new Label();

	private Value getLocationValue()
	{
		Value ret = new Value();
		ret.getNewChild( "location" ).setValue( location.getText() );
		return ret;
	}
	
	private void showLyrics()
	{
		Value val = getLocationValue();
		lyrics.setText( "Fetching lyrics..." );
		lyricsDialog.center();
		lyricsDialog.show();
		JolieService.Util.getInstance().call(
			"getLyrics", val, new EchoesCallback() {
			@Override
			public void onSuccess( Value response ) {
				lyrics.setHTML( response.strValue().replace( "\n", "<br/>" ) );
				lyricsDialog.center();
			}
		} );
	}
	
	private void waitForStateChange()
	{
		Value val = getLocationValue();
		val.getFirstChild( "logicalClock" ).setValue( logicalClock );
		JolieService.Util.getInstance().call(
			"waitForStateChange", val, new EchoesCallback() {
			@Override
			public void onSuccess( Value response ) {
				setWidgetValues( response );
				logicalClock = response.getFirstChild( "logicalClock" ).intValue();
				waitForStateChange();
			}
		} );
	}
	
	private int sid = -1;
	
	private void startClientSession()
	{
		Value val = getLocationValue();
		JolieService.Util.getInstance().call(
			"startClientSession", val, new EchoesCallback() {
			@Override
			public void onSuccess( Value response ) {
				setWidgetValues( response );
				sid = response.getFirstChild( "sid" ).intValue();
				logicalClock = response.getFirstChild( "logicalClock" ).intValue();
				
				Window.addWindowCloseListener( new WindowCloseListener() {
					public String onWindowClosing() {
						return null;
					}

					public void onWindowClosed() {
						closeClientSession();
					}
				} );
			}
		} );
	}
	
	private int logicalClock = 0;
	
	private void setWidgetValues( Value state )
	{
		state = state.getFirstChild( "state" );
		playlistBox.clear();
		for( Value v : state.getFirstChild( "playlist" ).getChildren( "song" ) ) {
			playlistBox.addItem( v.strValue() );
		}

		cpLabel.setText( state.getFirstChild( "nowPlaying" ).strValue() );

		int volume = state.getFirstChild( "volume" ).intValue();
		volumeMenu.setSelectedIndex( (volume + 4) / 5 );
	}
	
	private void createLyricsDialog()
	{
		lyricsDialog = new DialogBox();
		VerticalPanel vPanel = new VerticalPanel();
		vPanel.setHeight( "100%" );
		vPanel.setHorizontalAlignment( VerticalPanel.ALIGN_CENTER );
		vPanel.setVerticalAlignment( VerticalPanel.ALIGN_MIDDLE );
		lyricsDialog.add( vPanel );
		
		lyrics = new HTML();
		ScrollPanel scrollPanel = new ScrollPanel();
		scrollPanel.setWidth( "300px" );
		scrollPanel.setHeight( "250px" );
		scrollPanel.add( lyrics );
		vPanel.add( scrollPanel );
		
		Button close = new NativeButton( "Close" );
		close.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				lyricsDialog.hide();
			}
		} );
		vPanel.add( close );
	}
	
	private void playSongByIndex( int index )
	{
		Value val = getLocationValue();
		val.getNewChild( "index" ).setValue( index );
		JolieService.Util.getInstance().call(
			"playByIndex", val, new EchoesCallback() {
			@Override
			public void onSuccess( Value response ) {
			}
		} );
	}
	
	private void setVolume( String volume )
	{
		Value val = getLocationValue();
		val.setValue( volume );
		JolieService.Util.getInstance().call(
			"setVolume", val, new EchoesCallback() {
			@Override
			public void onSuccess( Value response ) {
			}
		} );
	}
	
	private void createAboutDialog()
	{
		aboutDialog = new DialogBox();
		VerticalPanel vPanel = new VerticalPanel();
		vPanel.setHorizontalAlignment( VerticalPanel.ALIGN_CENTER );
		aboutDialog.add( vPanel );
		vPanel.add( new HTML( "<strong>Echoes</strong>" ) );
		VerticalPanel cPanel = new VerticalPanel();
		vPanel.add( cPanel );
		cPanel.setHorizontalAlignment( VerticalPanel.ALIGN_CENTER );
		cPanel.addStyleName( "margintop-2em" );
		cPanel.add( new HTML( "(C) 2008, <a href=\"mailto:[email protected]\">Fabrizio Montesi</a>" ) );
		HTML oxygenTeam = new HTML(
			"Echoes logo by <a href=\"http://www.oxygen-icons.org/\" target=\"_new\">the Oxygen team</a>"
		);
		oxygenTeam.addStyleName( "margintop-1em" );
		cPanel.add( oxygenTeam );
		
		HTML license = new HTML(
			"License: <a href=\"http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\" target=\"_new\">GPLv2</a>"
		);
		license.addStyleName( "margintop-1em" );
		cPanel.add( license );
		
		HorizontalPanel hPanel = new HorizontalPanel();
		hPanel.setVerticalAlignment( HorizontalPanel.ALIGN_MIDDLE );
		hPanel.addStyleName( "margintop-1em" );
		HTML poweredBy = new HTML(
			"Powered by: "
		);
		hPanel.add( poweredBy );
		Image jolieImage = new Image( "images/jolie.png" );
		jolieImage.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				Window.open( "http://jolie.sourceforge.net/", "_blank", "" );
			}
		} );
		hPanel.add( jolieImage );
		cPanel.add( hPanel );
		
		Button closeButton = new NativeButton( "Close" );
		closeButton.addStyleName( "margintop-1em" );
		closeButton.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				aboutDialog.hide();
			}
		} );
		vPanel.add( closeButton );
	}
	
	private DialogBox lyricsDialog;
	private HTML lyrics;
	private ListBox playlistBox;
	private ListBox volumeMenu;
	private DialogBox aboutDialog;
	
	private final static String logoURL = "images/logo.png";
	
	public void onModuleLoad()
	{
		createLyricsDialog();
		
		Image.prefetch( logoURL );
		location.setText( "socket://localhost:10100" );
	
		VerticalPanel mainVPanel = new VerticalPanel();
		mainVPanel.setHorizontalAlignment( VerticalPanel.ALIGN_CENTER );
		RootPanel.get().add( mainVPanel );
		
		HorizontalPanel hPanel;
		hPanel = new HorizontalPanel();
		mainVPanel.add( hPanel );

		VerticalPanel vPanel = new VerticalPanel();
		hPanel.add( vPanel );
		VerticalPanel playlistVPanel = new VerticalPanel();
		playlistVPanel.setHorizontalAlignment( VerticalPanel.ALIGN_CENTER );
		playlistVPanel.setVerticalAlignment( VerticalPanel.ALIGN_MIDDLE );
		hPanel.add( playlistVPanel );
		
		vPanel.setHorizontalAlignment( VerticalPanel.ALIGN_CENTER );
		vPanel.setVerticalAlignment( VerticalPanel.ALIGN_MIDDLE );
		Image logo = new Image( logoURL );
		createAboutDialog();
		logo.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				aboutDialog.center();
				aboutDialog.show();
			}
		} );
		vPanel.add( logo );
		vPanel.addStyleName( "panel-rightborder" );
		
		//hPanel = new HorizontalPanel();
		DisclosurePanel dPanel = new DisclosurePanel( "Location", false );
		VerticalPanel locVPanel = new VerticalPanel();
		locVPanel.setHorizontalAlignment( HorizontalPanel.ALIGN_CENTER );
		locVPanel.add( location );
		final Button connectButton = new NativeButton( "Connect" );
		connectButton.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				startClientSession();
				waitForStateChange();
				connectButton.setText( "Connected" );
				connectButton.setEnabled( false );
			}
		} );
		
		dPanel.add( locVPanel );
		//hPanel.add( dPanel );
		vPanel.add( dPanel );
		vPanel.add( connectButton );
		
		//hPanel = new HorizontalPanel();
		Label l = new Label( "Currently playing" );
		l.addStyleName( "label-bold" );
		mainVPanel.add( l );
		mainVPanel.add( cpLabel );
		//mainvPanel.add( hPanel );
		
		HorizontalPanel buttonsPanel = new HorizontalPanel();
		mainVPanel.add( buttonsPanel );
		
		Button playButton = new NativeButton( "Play" );
		playButton.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				JolieService.Util.getInstance().call(
					"play", getLocationValue(), new EchoesCallback() {
					@Override
					public void onSuccess( Value response ) {
						//updateNowPlaying();
					}
				} );
			}
		} );
		
		Button pauseButton = new NativeButton( "Pause" );
		pauseButton.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				JolieService.Util.getInstance().call(
					"pause", getLocationValue(), new EchoesCallback() {
					@Override
					public void onSuccess( Value response ) {}
				} );
			}
		} );
		
		Button prevButton = new NativeButton( "&lt;" );
		prevButton.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				JolieService.Util.getInstance().call(
					"previous", getLocationValue(), new EchoesCallback() {
					@Override
					public void onSuccess( Value response ) {
						//updateNowPlaying();
					}
				} );
			}
		} );
		
		Button nextButton = new NativeButton( "&gt;" );
		nextButton.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				JolieService.Util.getInstance().call(
					"next", getLocationValue(), new EchoesCallback() {
					@Override
					public void onSuccess( Value response ) {
						//updateNowPlaying();
					}
				} );
			}
		} );

		buttonsPanel.add( prevButton );
		buttonsPanel.add( playButton );
		buttonsPanel.add( pauseButton );
		buttonsPanel.add( nextButton );
		
		playlistBox = new ListBox();
		playlistBox.setVisibleItemCount( 8 );
		playlistVPanel.add( playlistBox );
		playlistBox.setWidth( "250px" );
		
		playlistBox.addClickListener( new ClickListener() {
			public void onClick( Widget widget ) {
				playSongByIndex( playlistBox.getSelectedIndex() );
			}
		} );
		
		hPanel = new HorizontalPanel();

		Button showLyricsButton = new NativeButton( "Show lyrics" );
		showLyricsButton.addClickListener( new ClickListener() {
			public void onClick( Widget arg0 ) {
				showLyrics();
			}
		} );
		
		hPanel.add( showLyricsButton );
		playlistVPanel.add( hPanel );
		
		dPanel = new DisclosurePanel( "Volume" );
		playlistVPanel.add( dPanel );
		volumeMenu = new ListBox();
		dPanel.add( volumeMenu );
		addVolumeMenuItems( volumeMenu );
		volumeMenu.addChangeListener( new ChangeListener() {
			public void onChange( Widget arg0 ) {
				String volume = volumeMenu.getValue( volumeMenu.getSelectedIndex() );
				setVolume( volume );
			}
		} );
	}
	
	private void closeClientSession()
	{
		final DialogBox dialog = new DialogBox();
		dialog.add( new Label( "Exiting..." ) );
		dialog.center();
		dialog.show();
		Value v = getLocationValue();
		v.getNewChild( "sid" ).setValue( sid );
		JolieService.Util.getInstance().call(
			"closeClientSession", v, new EchoesCallback() {
			@Override
			public void onSuccess( Value response ) {
				dialog.hide();
			}
		} );
	}
	
	private void addVolumeMenuItems( ListBox volumeMenu )
	{
		volumeMenu.addItem( "0%", "0" );
		volumeMenu.addItem( "5%", "5" );
		volumeMenu.addItem( "10%", "10" );
		volumeMenu.addItem( "15%", "15" );
		volumeMenu.addItem( "20%", "20" );
		volumeMenu.addItem( "25%", "25" );
		volumeMenu.addItem( "30%", "30" );
		volumeMenu.addItem( "35%", "35" );
		volumeMenu.addItem( "40%", "40" );
		volumeMenu.addItem( "45%", "45" );
		volumeMenu.addItem( "50%", "50" );
		volumeMenu.addItem( "55%", "55" );
		volumeMenu.addItem( "60%", "60" );
		volumeMenu.addItem( "65%", "65" );
		volumeMenu.addItem( "70%", "70" );
		volumeMenu.addItem( "75%", "75" );
		volumeMenu.addItem( "80%", "80" );
		volumeMenu.addItem( "85%", "85" );
		volumeMenu.addItem( "90%", "90" );
		volumeMenu.addItem( "95%", "95" );
		volumeMenu.addItem( "100%", "100" );
	}
}