/*
 *  BasicButtonSound.java
 *  Cookbook
 *
 *  Copyright (c) 2001-2009 Flagstone Software Ltd. All rights reserved.
 *
 *  This code is distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 *  EXPRESS OR IMPLIED, AND Flagstone HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING
 *  WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 *  PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
 */

import com.flagstone.transform.*;
import com.flagstone.transform.util.*;

import java.awt.Font;
import java.util.*;

import java.io.IOException;
import java.util.zip.DataFormatException;

/*
 * This example shows how to create a button using FSDefineButton. The button 
 * displays a web page in a browser when clicked and also plays a sound.
 *
 * To run this example, type the following on a command line:
 *
 *     java -cp cookbook.jar BasicButtonSound sound-file file-out
 *
 * where
 *
 *     sound-file is the path to a file containing a WAVE or MP3 format sound
 *     which is played when a button is clicked.
 *
 *     file-out is the path where the file will be written. If no output file 
 *     is specified then a file named after the example will be written to the 
 *     current directory.

 */
public class BasicButtonSound
{
	public static void main(String[] args)
	{
        try
        {
        	String filename = args[0];
        	String out = args.length == 1 ? "BasicButtonSound.swf" : args[1];
        	BasicButtonSound example = new BasicButtonSound();         
            FSMovie movie = new FSMovie();            
            example.createMovie(movie, filename);
            movie.encodeToFile(out);
        }
        catch (Exception e)
        {
        	e.printStackTrace();
        }
	}
    
	void createMovie(FSMovie movie, String filename) throws IOException, DataFormatException
	{
		Font font = new Font("Arial", Font.PLAIN, 12);
		String buttonLabel = "Click Me!";
		
		FSTextConstructor textGenerator = new FSTextConstructor(movie.newIdentifier(), font);
		FSShapeConstructor path = new FSShapeConstructor();

		int layer = 1;       // initial layer in the display list
		int fontSize = 280;  // 280 twips == 14 point, 1 point == 20 twips

		/*
		 * Define margins added to define the width of the button relative to 
		 * the size of the label and the screen width relative to the width of 
		 * the button.
		 */
		int buttonMargin = 200; // The margin between the label and the edge of the button.
		int screenMargin = 400; // The margin between the edge of the button and the screen.

		/*
		 * Define colours used to fill the buttons in each of its states.
		 */
		FSColor lineColor = FSColorTable.black();
		FSColor shadowColor = FSColorTable.gray();
		FSColor upColor = FSColorTable.red();
		FSColor overColor = FSColorTable.orange();

		/*
		 * Define coordinate transform applied to the basic button shape 
		 * to perform a simple animation giving the impression the button
		 * was physically clicked.
		 */
		FSCoordTransform recess = new FSCoordTransform(60, 60);

		/*
		 * Define the shapes used to create the buttons.
		 *
		 * The size of the shapes is calculated relative to the bounding rectangle
		 * enclosing an arbitrary long label. The ascent of the text is used rather
		 * than the full height of the bounding rectangle as this gives better
		 * placement of the text relative to the button edges.
		 */
		FSDefineText2 label = textGenerator.defineText(movie.newIdentifier(), 
				buttonLabel, fontSize, lineColor);

		// define a 10 pixel margin around the text.
    
		int buttonWidth = label.getBounds().getWidth() + buttonMargin;
		int buttonHeight = -label.getBounds().getMinY() + buttonMargin;

		int lineWidth = 20;
		int cornerRadius = 100;

		/*
		 * The button will cast as shadow when it in the up state. Recessing the 
		 * button by changing the location of the shapes when the button is 
		 * clicked allows a very simple animation to be performed. More complex 
		 * animations can be created by using movie clips.
		 */
		int xShadow = 60;
		int yShadow = 60;
		
		path.add(new FSSolidLine(lineWidth, shadowColor));
		path.add(new FSSolidFill(shadowColor));
		path.rect(0, 0, buttonWidth, buttonHeight, cornerRadius);
		
		FSDefineShape2 shadow = path.defineShape(movie.newIdentifier());
			
		path.set(0, new FSSolidLine(lineWidth, lineColor));
		path.set(0, new FSSolidFill(upColor));
		path.rect(0, 0, buttonWidth, buttonHeight, cornerRadius);
		
		FSDefineShape2 upShape = path.defineShape(movie.newIdentifier());

		path.set(0, new FSSolidLine(lineWidth, lineColor));
		path.set(0, new FSSolidFill(overColor));
		path.rect(0, 0, buttonWidth, buttonHeight, cornerRadius);
		
		FSDefineShape2 overShape = path.defineShape(movie.newIdentifier());

		/*
		 * This button is created using the FSDefineButton class which only 
		 * defines actions when the button is clicked. The FSDefineButton2 class 
		 * supports a more complex model that allows actions to be performed for 
		 * a wide range of different button events.
		 */
		ArrayList records = new ArrayList();

		/*
		 * Used to hold the width and height of the bounding rectangle that
		 * encloses the button labels.
		 */
		int xOffset = -label.getBounds().getWidth()/2;
		int yOffset = (buttonHeight - label.getBounds().getHeight())/2;

		/*
		 * Create the FSButto objects that define the button's appearance. More 
		 * than one button record can be defined for a given state allowing for 
		 * example button definitions to be reused with only the label changing. 
		 * The layer number controls the order in which the shapes are displayed.
		 *
		 * Use one of the button shapes to define the active area where the 
		 * button will respond to events generated by the mouse.
		 */
		records.add(new FSButton(FSButton.Active, upShape.getIdentifier(), layer++));

		/*
		 * Define the appearance of the button in the up state. A shape giving a 
		 * drop shadow effect is placed in the background and the label is in 
		 * the foreground.
		 */
		records.add(new FSButton(FSButton.Up, shadow.getIdentifier(), layer++, recess));
		records.add(new FSButton(FSButton.Up, upShape.getIdentifier(), layer++));
		records.add(new FSButton(FSButton.Up, label.getIdentifier(), layer++, 
			new FSCoordTransform(xOffset, yOffset)));

		/*
		 * The button appears the same when the mouse is over the active area. 
		 * Only the colour changes to highlight the button. The drop shadow must 
		 * still be drawn.     
		 */
		records.add(new FSButton(FSButton.Over, shadow.getIdentifier(), layer++, recess));
		records.add(new FSButton(FSButton.Over, overShape.getIdentifier(), layer++));
		records.add(new FSButton(FSButton.Over, label.getIdentifier(), layer++, 
			new FSCoordTransform(xOffset, yOffset)));

		/*
		 * The button appears is recessed when it is clicked so the shape for the drop shadow is
		 * not required.
		 */
		records.add(new FSButton(FSButton.Down, overShape.getIdentifier(), layer++, recess));
		records.add(new FSButton(FSButton.Down, label.getIdentifier(), layer++, 
			new FSCoordTransform(xOffset + xShadow, yOffset + yShadow)));

		/*
		 * When the button is clicked a web page will be loaded into the web 
		 * browser. The browser must be running for this to work, the Flash Player 
		 * won't launch the browser by itself.
		 */
		ArrayList actions = new ArrayList();

		actions.add(new FSGetUrl("http://www.flagstonesoftware.com", ""));

		FSDefineButton button = new FSDefineButton(movie.newIdentifier(), 
			records, actions);

		/*
		 * Now define the sound that will be played when the button is clicked. 
		 */

		FSSoundConstructor soundGenerator = new FSSoundConstructor(filename);

        FSDefineSound sound = soundGenerator.defineSound(movie.newIdentifier());
        
		FSButtonSound buttonSound = new FSButtonSound(button.getIdentifier(), 
			FSButtonEvent.Release, new FSSound(sound.getIdentifier(), 0));	

		/***************************************************
		 *     Put all the objects together in a movie
		 ***************************************************/

		/*
		 * Make the screen tall enough for a column of five buttons.
		 */
		int screenWidth = buttonWidth + 2*screenMargin;
		int screenHeight = buttonHeight + 2*screenMargin;
        
		movie.setFrameSize(new FSBounds(0, 0, screenWidth, screenHeight));
		movie.setFrameRate(1.0f);
		movie.add(new FSSetBackgroundColor(FSColorTable.lightblue()));

		// Add the font definition for the text labels
		movie.add(textGenerator.defineFont());

		// Add the shapes used to define the buttons
		movie.add(shadow);
		movie.add(upShape);
		movie.add(overShape);
		movie.add(label);
		movie.add(button);
		movie.add(sound);
		movie.add(buttonSound);

		movie.add(new FSPlaceObject2(button.getIdentifier(), layer++, 
			screenWidth/2 , screenHeight/2));

		movie.add(new FSShowFrame());
	}
}