/*
 *
 * Copyright 2010 PC-NG Inc. All rights reserved.
 * PC-NG PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.nexiwave.search.client.sample;

import java.util.Calendar;

import javax.activation.DataHandler;

import com.nexiwave.search.client.SearchService2Stub;
import com.nexiwave.search.client.SearchService2Stub.AddByURLResponse;
import com.nexiwave.search.client.SearchService2Stub.AddExtResponse;
import com.nexiwave.search.client.SearchService2Stub.AddLocalFileResponse;
import com.nexiwave.search.client.SearchService2Stub.AudioUploadData;
import com.nexiwave.search.client.SearchService2Stub.DecodingProfile;
import com.nexiwave.search.client.SearchService2Stub.ListAllRecordingInfoResponse;
import com.nexiwave.search.client.SearchService2Stub.ListDecodingProfilesResponse;
import com.nexiwave.search.client.SearchService2Stub.ListRecordingInfoResponse;
import com.nexiwave.search.client.SearchService2Stub.Lookup;
import com.nexiwave.search.client.SearchService2Stub.LookupResponse;
import com.nexiwave.search.client.SearchService2Stub.QueryProcessingStatus;
import com.nexiwave.search.client.SearchService2Stub.QueryProcessingStatusResponse;
import com.nexiwave.search.client.SearchService2Stub.QueryResponse;
import com.nexiwave.search.client.SearchService2Stub.Recording;
import com.nexiwave.search.client.SearchService2Stub.RecordingProcessingStatus;

/**
 * This class will demonstrate nexiwave's Audio Search Web Service usage.
 * 
 * Some preparation steps:
 * 1. Obtain a test account: you can either sign up a free trial account at nexiwave.com, 
 * 												or contact support@nexiwave.com. 
 * 2. Obtain the groupId for your integrator group: if you sign up 
 * 
 * @author bjiang
 *
 */
public class SearchServiceSampleClient extends AbstractSampleClient{

	/**
	 * Main method.
	 * @param args
	 * @throws Exception
	 */
	public static void main(String args[]) throws Exception{
		SearchServiceSampleClient client=new SearchServiceSampleClient("https://api.nexiwave.com", "your_userId", "your_pwd");
		
		client.testAll();
	}
	
	/**
	 * Constructor
	 * @param server_loc
	 * @param userId
	 * @param passwd
	 * @throws Exception
	 */
	public SearchServiceSampleClient(String server_loc, String userId, String passwd)throws Exception {
		this(server_loc, 0, userId, passwd);
	}

	/**
	 * Constructor
	 * @param server_loc
	 * @param userId
	 * @param groupID: only supply if you know the groupID, otherwise, use 0.
	 * @param passwd
	 * @throws Exception
	 */
	public SearchServiceSampleClient(String server_loc, long groupId, String userId, String passwd)throws Exception {
		super(server_loc, groupId, userId, passwd);
	}
	
	/**
	 * Constructor
	 * @param server_loc
	 * @param data
	 * @throws Exception
	 */
	public SearchServiceSampleClient(String server_loc, TestData data) throws Exception{
		super(server_loc, data);
	}
	
	/**
	 * Test all web services.
	 * @throws Exception
	 */
	public void testAll()throws Exception{
		testBasicCalls();
		
		testAdvancedCalls();

		System.out.println("Done all testing.");
	}
	
	/**
	 * Testing some basic calls
	 * @throws Exception
	 */
	public void testBasicCalls()throws Exception{
		
		// quick and directy way to upload an audio
		long recordingId=testAddByURL();
		
		testAddLocalFile();
		
		// check the processing status of this uploaded audio
		testQueryRecordingProcessingStatus(recordingId);
		
		// looking up this recording by a key that we have just supplied.
		testLookup();

		// try search the indexed audio portion of the audio:
		testQuery();
		
		// delete this audio from nexiwave audio search platform (note: this is a soft remove)
		testRemove(recordingId);
		
	}
	
	/**
	 * This is to demo the full capability of nexiwave service.
	 * @throws Exception
	 */
	public void testAdvancedCalls()throws Exception{
		
		// list a current supported decoding profiles
//		listSupportedDecodingProfiles();
		
		// the full version of uploading an audio
		testAddExt();
		
		// list all recordings of an account.
		testListAllRecordings();
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Individual test methods below:
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * Quick simple way to upload an audio thru an URL. What you need is:
	 * 1. a nexiwave account
	 * 2. an HTTP(S) url for an audio file (mp3, wav, ogg)
	 * 
	 */
	public long testAddByURL()throws Exception{
		// testing add audio:
		SearchService2Stub.AddByURL req = new SearchService2Stub.AddByURL();
		
		// Create the authentication data to the SOAP call.
		// AuthData contains three pieces of data:
		//      1. userId: this can be either user's email, or the id that was assigned to the user.
		//      2. password: the password in cleartext.
		//      3. groupId: each API integrator needs to receive a groupId from nexiwave. 
		//                          You should associate the authData to your own group. 
		//                          If groupId is null or 0, the default group (the nexiwave trial users group) will be used
		//                          If you are using a test account signed up from nexiwave.com, you can let the groupId to default.
		//                          For more info, see the groupAdmin service sample client (GroupAdminServiceSampleClient.java) and group admin document.
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();		
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());

		req.setAuthData(authData);
		req.setExternalKey("my_external_key_12432");
		req.setMediaURL(this.data.getSmallAudioFileURL());
		
		AddByURLResponse resAdd = getStub().addByURL(req);
		long newRecordingId=resAdd.get_return();
		System.out.println("add result " + newRecordingId);
		
		if(newRecordingId<=0)
			throw new RuntimeException("Hmm, invalid recording id returned.");
		
		return newRecordingId;
	}

	/**
	 * Quick simple way to upload an local audio file. What you need is:
	 * 1. a nexiwave account
	 * 2. a local audio file (mp3, wav, ogg)
	 * 
	 */
	public long testAddLocalFile()throws Exception{
		// testing add audio:
		SearchService2Stub.AddLocalFile req = new SearchService2Stub.AddLocalFile();
		
		// Create the authentication data to the SOAP call.
		// AuthData contains three pieces of data:
		//      1. userId: this can be either user's email, or the id that was assigned to the user.
		//      2. password: the password in cleartext.
		//      3. groupId: each API integrator needs to receive a groupId from nexiwave. 
		//                          You should associate the authData to your own group. 
		//                          If groupId is null or 0, the default group (the nexiwave trial users group) will be used
		//                          If you are using a test account signed up from nexiwave.com, you can let the groupId to default.
		//                          For more info, see the groupAdmin service sample client (GroupAdminServiceSampleClient.java) and group admin document.
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();		
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());

		req.setAuthData(authData);
		req.setExternalKey("my_external_key_12432");
		req.setMediaData(new DataHandler(data.getLocalAudioFile().toURI().toURL()));
		req.setFileName(data.getLocalAudioFile().getName());
		
		AddLocalFileResponse resAdd = getStub().addLocalFile(req);
		long newRecordingId=resAdd.get_return();
		System.out.println("add result " + newRecordingId);
		
		if(newRecordingId<=0)
			throw new RuntimeException("Hmm, invalid recording id returned.");
		
		return newRecordingId;
	}

	/**
	 * the full version of uploading an audio.
	 * @return
	 * @throws Exception
	 */
	public long testAddExt()throws Exception{
		// testing add audio:
		SearchService2Stub.AddExt req = new SearchService2Stub.AddExt();
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();
		req.setAuthData(authData);
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());
		
		AudioUploadData data=new AudioUploadData();
		data.setMediaFile2TranscribeURL(this.data.getSmallAudioFileURL());
		
		data.setDisplayTitle("Custom Audio Title");
		
		// maybe your audio happened in the past:
		Calendar cal=Calendar.getInstance();
		cal.add(Calendar.HOUR, -2);
		cal.add(Calendar.YEAR, -2);
		{
			// ////////////////////////////////
			// all of these data are optional:
			data.setExternalKey("test123");
			data.setTargetDecodingConfigName("Fast");
//			data.setHttpNotifyBackURLOnFinish("http://your_domain.com/app/callOnFinish.do");
			
			data.setNotes("my notes");
			
			// the real happening time in your environment:
			data.setActualStartTimeInMS(cal.getTimeInMillis());
		}
		
		req.setData(data);
		
		AddExtResponse resAdd = getStub().addExt(req);
		long newRecordingId=resAdd.get_return();
		System.out.println("add result " + newRecordingId);
		
		if(newRecordingId<=0)
			throw new RuntimeException("Hmm, invalid recording id returned.");
		
		// verification:
		SearchService2Stub.ListRecordingInfo req1 = new SearchService2Stub.ListRecordingInfo();
		req1.setAuthData(authData);
		req1.setRecordingId(newRecordingId);
		
		ListRecordingInfoResponse resp = getStub().listRecordingInfo(req1);
		Recording r=resp.get_return();
		
		Calendar d=r.getUploadTime();
		System.out.println("So, the server said the recording was created at: "+d);
		long diff=Math.abs(d.getTimeInMillis()-cal.getTimeInMillis());
		
		if(diff>10000){
			System.out.println("Hmm, expecting only small time diff here. There is "+diff+"ms difference");
		}
		else if(diff>0){
			System.out.println("There is "+diff+"ms difference here, which is acceptable.");			
		}
		
		return newRecordingId;
	}


	public void testListAllRecordings() throws Exception{
		SearchService2Stub.ListAllRecordingInfo req=new SearchService2Stub.ListAllRecordingInfo();
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();
		req.setAuthData(authData);
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());
		
		ListAllRecordingInfoResponse res = getStub().listAllRecordingInfo(req);
		System.out.println("total recordings: " + res.get_return());
	}
	
	public void testQuery()throws Exception{
		// testing query:
		SearchService2Stub.Query req = new SearchService2Stub.Query();
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();
		req.setAuthData(authData);
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());

		req.setQuery("improvement");
		
		QueryResponse res = getStub().query(req);
		System.out.println("query result " + res.get_return());
	}
	
	public void testQueryRecordingProcessingStatus(long recordingId)throws Exception{
		SearchService2Stub.QueryProcessingStatus req=new QueryProcessingStatus();
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();
		req.setAuthData(authData);
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());

		req.setRecordingId(recordingId);
		
		QueryProcessingStatusResponse resp=getStub().queryProcessingStatus(req);
		RecordingProcessingStatus status=resp.get_return();
		System.out.println("Recording processing status for "+recordingId+": "+status.getStatus());
	}
	
	public void testLookup()throws Exception{
		Lookup req=new Lookup();
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();
		req.setAuthData(authData);
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());

		req.setExternalKey("my_external_key_12432");
		
		LookupResponse res = getStub().lookup(req);
		System.out.println("Lookup result: "+res.get_return());
	}
	
	public void testRemove(long recordingId)throws Exception{
		System.out.println("Deleting "+recordingId);
		// testing remove:
		SearchService2Stub.Remove req=new SearchService2Stub.Remove();
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();
		req.setAuthData(authData);
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());

		req.setRecordingId(recordingId);
		getStub().remove(req);
	}
	
	/*
	 * List supported decoding profiles
	 */	
	public void listSupportedDecodingProfiles()throws Exception{
		SearchService2Stub.ListDecodingProfiles req=new SearchService2Stub.ListDecodingProfiles();
		SearchService2Stub.AuthData authData=new SearchService2Stub.AuthData();
		req.setAuthData(authData);
		authData.setEmail(data.getUserId());
		authData.setPasswd(data.getPasswd());
		authData.setGroupId(data.getChildAccountGroupId());
		
		ListDecodingProfilesResponse resp=getStub().listDecodingProfiles(req);
		System.out.println("nexiwave support "+resp.get_return().length+" decoding profiles:");
		for(DecodingProfile dp:resp.get_return()){
			System.out.println("\t"+dp.getName()+": "+dp.getDescription());			
		}
	}


}
