package flickruppr.ui;

import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import com.aetrion.flickr.Flickr;
import com.aetrion.flickr.FlickrException;
import com.aetrion.flickr.REST;
import com.aetrion.flickr.RequestContext;
import com.aetrion.flickr.auth.Auth;
import com.aetrion.flickr.auth.AuthInterface;
import com.aetrion.flickr.photos.GeoData;
import com.aetrion.flickr.photos.geo.GeoInterface;
import com.aetrion.flickr.uploader.UploadMetaData;
import com.aetrion.flickr.uploader.Uploader;
import com.buglabs.bug.module.camera.pub.ICameraDevice;
import com.buglabs.bug.module.gps.pub.IPositionProvider;
import com.buglabs.bug.module.gps.pub.LatLon;
import com.buglabs.bug.module.lcd.pub.IModuleDisplay;
import com.buglabs.bug.module.motion.pub.IMotionObserver;
import com.buglabs.bug.module.motion.pub.IMotionSubject;

/**
 * FlickrUpprApp is the main application class. It displays a user interface
 * to authenticate against flickr. When it detects motion via the IMotionObserver
 * interface it takes a snapshot, geo tags it, and uploads it to the user's 
 * flickr account.
 * 
 * Four services are required:
 * 	IModuleDisplay - To display the authentication UI.
 *  ICameraDevice - To retrieve an image from the camera
 *  IMotionSubject - To listen for motion events.
 *  IPositionProvider - To retrieve lattitude and longitude from gps.
 *  
 * @author Angel Roman - Angel.Roman@mdesystems.com
 * 
 */
public class FlickrUpprApp implements IMotionObserver {
	/**
	 * Flickr API KEY. If you are interested in creating your own flickr
	 * application, please visit http://www.flickr.com/services/api/keys/apply/
	 * and apply for a key.
	 */
	public static final String API_KEY = "75cf15a5751158c2fd269859a11fa063";
	
	/**
	 * Flickr Secret shared key. If you are interested in creating your own flickr
	 * application, please visit http://www.flickr.com/services/api/keys/apply/
	 * and apply for a key.
	 */
	public static final String SECRET_KEY = "d493a54ca0b02047";
	
	/**
	 * Mobile authentication URL. If you are interested in creating your own flickr
	 * application, please visit http://www.flickr.com/services/api/keys/apply/
	 * and apply for a key.
	 */
	public static final String AUTH_URL = "http://www.flickr.com/auth-72157602155790115";

	/**
	 * Auth object user to stored full token. 
	 */
	private Auth auth;
	
	/**
	 * Flickr transport to use.
	 */
	private REST rest;
	
	/**
	 * Handle to Flickr APIs main class.
	 */
	private Flickr flickr;
	
	/**
	 * Handle to AWT java.awt.Frame return by IModuleDisplay.
	 */
	private Frame frame;
	
	/**
	 * Text field used to retrieve user's 9-digit token.
	 */
	private TextField txtToken;
	
	/**
	 * Handle to the Display service.
	 */
	private IModuleDisplay disp;
	
	/**
	 * Handle to the Camera service.
	 */
	private ICameraDevice camera;
	private IPositionProvider position;

	private IMotionSubject motion;

	/**
	 * FlickrUpprApp constructor. It requires valid IModuleDisplay, 
	 * IMotionSubject, ICameraDevice and IPositionProvider services.
	 * 
	 * @param disp
	 * @param motion
	 * @param camera
	 * @param position
	 */
	public FlickrUpprApp(IModuleDisplay disp, IMotionSubject motion, ICameraDevice camera, IPositionProvider position) {
		this.disp = disp;
		this.camera = camera;
		this.position = position;
		this.motion = motion;
	}

	/**
	 * Requests an AWT Frame from IModuleDisplay service and 
	 * populates it to request user authentication information.
	 *
	 */
	public void createUI() {
		this.frame = disp.getFrame();
		frame.setLayout(new GridLayout(5, 1));

		Label lblURL1 = new Label("Please visit: ");
		TextField txtURL = new TextField(AUTH_URL);
		txtURL.setEditable(false);
		Label lblURL3 = new Label("and enter the 9 digit token below.");

		frame.add(lblURL1);
		frame.add(txtURL);
		frame.add(lblURL3);

		txtToken = new TextField();
		frame.add(txtToken);

		Button btnAuth = new Button("Authenticate");
		btnAuth.addActionListener(new ActionListener(){

			public void actionPerformed(ActionEvent event) {
				try {
					String miniToken = txtToken.getText();
					miniToken.trim();
					if(miniToken != null && miniToken.length() == 9) {
						rest = new REST();
						rest.setHost("www.flickr.com");
						flickr = new Flickr(API_KEY, rest);
						RequestContext context = RequestContext.getRequestContext();
						context.setSharedSecret(SECRET_KEY);
						AuthInterface authIface = flickr.getAuthInterface();
						auth = authIface.getFullToken(miniToken);

						System.out.println("Token: " + auth.getToken());
						motion.register(FlickrUpprApp.this);
						frame.dispose();
					}
				} catch (ParserConfigurationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SAXException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (FlickrException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}});

		frame.add(btnAuth);
	}

	/**
	 * Displays the frame.
	 *
	 */
	public void show() {
		frame.show();
	}

	/**
	 * Disposes the frame.
	 *
	 */
	public void dispose(){
		if(motion != null) {
			motion.unregister(this);
		}
		
		frame.dispose();
	}

	/**
	 * Invoked when motion is detected by the IMotionSubject.
	 * 
	 * http://en.wikipedia.org/wiki/Observer_pattern
	 * 
	 */
	public void motionDetected() {
		
		//Tells flickr which api is contacting it and sets the user authentication.
		RequestContext context = RequestContext.getRequestContext();
		if(auth != null) {
			context.setAuth(auth);
			context.setSharedSecret(SECRET_KEY);
		} else {
			return;
		}
		
		/**
		 * Set up the Upload information, capture an image from the ICameraDevice service,
		 * uploat the image to user's account, geo tag the photo using the information 
		 * from IPositionProvider.
		 */
		try {
			UploadMetaData metaData = new UploadMetaData();
			metaData.setTitle("BUG");
			Uploader upload = new Uploader(API_KEY, rest);
			String photoId = upload.upload(camera.getImageInputStream(), metaData);
			
			LatLon latLon = position.getLatitudeLongitude();
			
			GeoData geodata = new GeoData(Double.toString(latLon.longitude),
					Double.toString(latLon.latitude),
					"16");
			
			GeoInterface geo = flickr.getPhotosInterface().getGeoInterface();
			geo.setLocation(photoId, geodata);

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FlickrException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}