package dspControl;

import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.http.HttpSession;
import org.apache.beehive.netui.pageflow.PageFlowController;
import org.apache.beehive.netui.pageflow.annotations.Jpf;
import org.apache.beehive.controls.api.bean.Control;

import controls.DSPControlFile;
import org.apache.beehive.netui.pageflow.Forward;

import weblogic.jndi.Environment;

/*
 * Examples of calling ALDSP via an ALDSP Control
 * For an actual example of a web application using ALDSP, 
 * search for Samples in ALDSP edocs
 */

@Jpf.Controller()
public class DspControlController extends PageFlowController {
	private static final long serialVersionUID = 1L;
	
	//public static retailer.impl.PROFILE_SERVICEImpl[]profileServiceBeans=null; 
	public static String[]profileServiceStrings=null;
	public static String outputString=null;
	
	String clientType="java";
	String uri="t3://localhost:7001";
	String username= "weblogic";
	String password="weblogic";
	enum ClassloaderType { noclassloader, currentthread, other};
	ClassloaderType classloaderType=ClassloaderType.noclassloader;
	transient java.io.Writer out=new java.io.PrintWriter(System.out);
	String className=this.getClass().getName().substring(this.getClass().getName().lastIndexOf('.')+1);
	String runningIn=this.getClass().getClassLoader().equals(com.bea.dsp.das.DASResult.class.getClassLoader()) ? "standalone" : "webapp";
	commonj.sdo.helper.XMLHelper xh = null;
	commonj.sdo.helper.DataFactory factory = null;
	
	@Control
	private DSPControlFile DSPControlFile;

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward begin() {
		
		out("--------------------------------------------------------------");
		if(! "java".equals(clientType) && ! "webservice".equals(clientType)){
			out("clientType must be java or webservice");
			return new Forward("default");
		}
		if(ClassloaderType.noclassloader != classloaderType){
			out("ClassloaderType must be noclassloader");
			return new Forward("default");
		}
		
		try {
		
			commonj.sdo.helper.HelperContext hc = com.bea.dsp.das.HelperContextCache.get("RetailDataspace");
			xh = hc.getXMLHelper();
			factory = hc.getDataFactory();
		}catch(Exception e){
			e.printStackTrace();
		}
		Forward forward = new Forward("success");
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward client(Object form) {
		StringBuffer query=new StringBuffer();
		query.append("declare variable $customerId as xs:string external;\n");
		query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
		query.append("tns:getCustomerByCustID($customerId)");
		com.bea.ld.ExternalVariables extVariables=new com.bea.ld.ExternalVariables();
		extVariables.setElement(new javax.xml.namespace.QName("customerId"), "CUSTOMER4", true);
		Object[] o=DSPControlFile.executeQuery(query.toString(), extVariables );
		outputString=dataObjectsToString(o);
		Forward forward = new Forward("success");
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward clientComplexArg() {
		commonj.sdo.DataObject profileService =(commonj.sdo.DataObject)factory.create("urn:retailer",
		"PROFILE_SERVICE");
		com.bea.dsp.sdo.SDOUtil.setElementName(profileService,
				"urn:retailer", "PROFILE");
		commonj.sdo.DataObject profile = profileService.createDataObject("PROFILE");
		profile.set("CustomerID", "CUSTOMER4"); 
		profile.set("FirstName", "dummyFirstName"); 
		profile.set("LastName", "dummyLastName");
		profile.set("CustomerSince", "2001-01-01");
		profile.set("EmailAddress", "dummyEmailAddress");
		profile.set("TelephoneNumber", "8885551212");
		
		com.bea.ld.ExternalVariables extVariables=new com.bea.ld.ExternalVariables();
		extVariables.setElement(new javax.xml.namespace.QName("profile"), dataObject2String(xh,profileService), true);
		StringBuffer query=new StringBuffer();
		query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
		query.append("declare namespace retailer='urn:retailer';\n");
		query.append("declare variable $profile as element(retailer:PROFILE) external;\n");
		query.append("tns:getServiceCase($profile)");
		Object[] cases=DSPControlFile.executeQuery(query.toString(), extVariables);
		outputString=dataObjectsToString(cases);
		Forward forward = new Forward("success");
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward clientComplexArgList() {
		
		commonj.sdo.DataObject profileService =(commonj.sdo.DataObject)factory.create("urn:retailer",
		"PROFILE_SERVICES");
		com.bea.dsp.sdo.SDOUtil.setElementName(profileService,
				"urn:retailer", "PROFILES");
		commonj.sdo.DataObject profile = profileService.createDataObject("PROFILE");
		profile.set("CustomerID", "CUSTOMER4"); 
		profile.set("FirstName", "dummyFirstName"); 
		profile.set("LastName", "dummyLastName");
		profile.set("CustomerSince", "2001-01-01");
		profile.set("EmailAddress", "dummyEmailAddress");
		profile.set("TelephoneNumber", "8885551212");
		
		profile = profileService.createDataObject("PROFILE");
		profile.set("CustomerID", "CUSTOMER6"); 
		profile.set("FirstName", "dummyFirstName"); 
		profile.set("LastName", "dummyLastName");
		profile.set("CustomerSince", "2001-01-01");
		profile.set("EmailAddress", "dummyEmailAddress");
		profile.set("TelephoneNumber", "8885551212");
	
		com.bea.ld.ExternalVariables extVariables=new com.bea.ld.ExternalVariables();
		extVariables.setElement(new javax.xml.namespace.QName("profiles"), dataObject2String(xh,profileService), true);
		StringBuffer query=new StringBuffer();
		query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
		query.append("declare namespace retailer='urn:retailer';\n");
		query.append("declare variable $profiles as element(retailer:PROFILES) external;\n");
		query.append("tns:getServiceCases($profiles)");
		Object[] cases=DSPControlFile.executeQuery(query.toString(), extVariables);
		outputString=dataObjectsToString(cases);

		Forward forward = new Forward("success");
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward clientComplexArgs_andCRUD() {
		
		// array to hold data objects
		
		retailer.PROFILE_SERVICE[] profileServices = new retailer.PROFILE_SERVICE[2];

		// dataobject argument - type found in signature 
		
		commonj.sdo.DataObject profileService1 =(commonj.sdo.DataObject)factory.create("urn:retailer",
		"PROFILE_SERVICE");
		
		// now we set the name to be the element name we found in the function signature ...
		
		com.bea.dsp.sdo.SDOUtil.setElementName(profileService1,
				"urn:retailer", "PROFILE");
		
		profileServices[0]=(retailer.PROFILE_SERVICE)profileService1;

		commonj.sdo.DataObject profile = profileService1.createDataObject("PROFILE");
		profile.set("CustomerID", "CUSTOMER44"); 
		profile.set("FirstName", "dummyFirstName"); 
		profile.set("LastName", "dummyLastName44");
		profile.set("CustomerSince", "2001-01-01");
		profile.set("EmailAddress", "dummyEmailAddress");
		profile.set("TelephoneNumber", "8885551212");
		
		commonj.sdo.DataObject profileService2 =(commonj.sdo.DataObject)factory.create("urn:retailer",
		"PROFILE_SERVICE");
		com.bea.dsp.sdo.SDOUtil.setElementName(profileService2,
				"urn:retailer", "PROFILE");
		
		profileServices[1]=(retailer.PROFILE_SERVICE)profileService2;
		
		profile = profileService2.createDataObject("PROFILE");
		profile.set("CustomerID", "CUSTOMER55"); 
		profile.set("FirstName", "dummyFirstName"); 
		profile.set("LastName", "dummyLastName55");
		profile.set("CustomerSince", "2001-01-01");
		profile.set("EmailAddress", "dummyEmailAddress");
		profile.set("TelephoneNumber", "8885551212");
		
		StringBuffer query=new StringBuffer();
		query.append("declare variable $customerId as xs:string external;\n");
		query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
		query.append("tns:getCustomerByCustID($customerId)");
		com.bea.ld.ExternalVariables extVariables=new com.bea.ld.ExternalVariables();
		extVariables.setElement(new javax.xml.namespace.QName("customerId"), "CUSTOMER44", true);
		Object[] returnedProfileServices=DSPControlFile.executeQuery(query.toString(), extVariables );

		// There is currently no way to call "update" producedures from the 'dynamic' API
		// in a DSP Control, so use the static API instead
		
		outputString="";
		if(returnedProfileServices.length==0) {
			outputString=outputString +"ADDING: \n";
			/*
			extVariables=new com.bea.ld.ExternalVariables();
			extVariables.setElement(new javax.xml.namespace.QName("profile"), dataObject2String(xh,profileServices), true);
			query=new StringBuffer();
			query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
			query.append("declare namespace retailer='urn:retailer';\n");
			query.append("declare variable $profile as element(retailer:PROFILE)* external;\n");
			query.append("tns:createPROFILE($profile)");
			returnedProfileServices=DSPControlFile.executeProcedure(query.toString(), extVariables);
			*/
			returnedProfileServices=DSPControlFile.createPROFILE(profileServices);
			outputString=outputString + dataObjectsToString(returnedProfileServices);

		} else {
			commonj.sdo.DataObject dObj= (commonj.sdo.DataObject)returnedProfileServices[0];
			if("dummyLastName44".equals(dObj.get("PROFILE/LastName"))){
				outputString=outputString +"UPDATING: \n";
				outputString=outputString + dataObjectsToString(profileServices);
				com.bea.dsp.sdo.SDOUtil.enableChanges(dObj);
				dObj.set("PROFILE/LastName", "Smith");
				DSPControlFile.updatePROFILE(new retailer.PROFILE_SERVICE[]{(retailer.PROFILE_SERVICE)dObj});
				/*
				extVariables=new com.bea.ld.ExternalVariables();
				extVariables.setElement(new javax.xml.namespace.QName("profile"), dataObject2String(xh,dObj), true);
				query=new StringBuffer();
				query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
				query.append("declare namespace retailer='urn:retailer';\n");
				query.append("declare variable $profile as changed-element(retailer:PROFILE)* external;\n");
				query.append("tns:updatePROFILE($profile)");
				DSPControlFile.executeProcedure(query.toString(), extVariables);
				*/
			} else {
				outputString=outputString +"DELETING: \n";
				outputString=outputString + dataObjectsToString(returnedProfileServices);
				DSPControlFile.deletePROFILE(new retailer.PROFILE_SERVICE[]{(retailer.PROFILE_SERVICE)dObj});
				
				/*
				extVariables=new com.bea.ld.ExternalVariables();
				extVariables.setElement(new javax.xml.namespace.QName("profile"), dataObject2String(xh,returnedProfileServices), true);
				query=new StringBuffer();
				query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
				query.append("declare namespace retailer='urn:retailer';\n");
				query.append("declare variable $profile as element(retailer:PROFILE)* external;\n");
				query.append("tns:deletePROFILE($profile)");
				DSPControlFile.executeProcedure(query.toString(), extVariables);
 				*/
		
				query=new StringBuffer();
				query.append("declare variable $customerId as xs:string external;\n");
				query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
				query.append("tns:getCustomerByCustID($customerId)");
				extVariables=new com.bea.ld.ExternalVariables();
				extVariables.setElement(new javax.xml.namespace.QName("customerId"), "CUSTOMER55", true);
				returnedProfileServices=DSPControlFile.executeQuery(query.toString(), extVariables );
		

				if(returnedProfileServices.length>0){
					dObj= (commonj.sdo.DataObject)returnedProfileServices[0];
					outputString=outputString + dataObjectsToString(returnedProfileServices);
					DSPControlFile.deletePROFILE(new retailer.PROFILE_SERVICE[]{(retailer.PROFILE_SERVICE)dObj});
					
					/*
					extVariables=new com.bea.ld.ExternalVariables();
					extVariables.setElement(new javax.xml.namespace.QName("profile"), dataObject2String(xh,returnedProfileServices), true);
					query=new StringBuffer();
					query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
					query.append("declare namespace retailer='urn:retailer';\n");
					query.append("declare variable $profile as element(retailer:PROFILE)* external;\n");
					query.append("tns:deletePROFILE($profile)");
					DSPControlFile.executeProcedure(query.toString(), extVariables);
					*/
				}
			}
		}

		Forward forward = new Forward("success");
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward clientSimpleReturn() {	
		outputString="";
		StringBuffer query=new StringBuffer();
		query.append("declare variable $customerId as xs:string external;\n");
		query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
		query.append("tns:getOrderCount($customerId)");
		com.bea.ld.ExternalVariables extVariables=new com.bea.ld.ExternalVariables();
		extVariables.setElement(new javax.xml.namespace.QName("customerId"), "CUSTOMER4", true);
		Object[] returnedProfileServices=DSPControlFile.executeQuery(query.toString(), extVariables );
		outputString=outputString + dataObjectsToString(new Object[]{returnedProfileServices});
		
		
		query=new StringBuffer();
		query.append("declare variable $customerId as xs:string external;\n");
		query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
		query.append("tns:getOrderCounts($customerId)");
		extVariables=new com.bea.ld.ExternalVariables();
		extVariables.setElement(new javax.xml.namespace.QName("customerId"), "CUSTOMER4", true);
		returnedProfileServices=DSPControlFile.executeQuery(query.toString(), extVariables );

		outputString=outputString + dataObjectsToString(returnedProfileServices);	
		Forward forward = new Forward("success");
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward clientWithAudit() {
		
		String[] attributes = new String[] { "common", "query" };
		
		com.bea.dsp.RequestConfig reqConfig = new com.bea.dsp.RequestConfig();
		reqConfig.enableFeature(com.bea.dsp.RequestConfig.RETURN_DATA_SERVICE_AUDIT);
		reqConfig.setStringArrayAttribute(
				com.bea.dsp.RequestConfig.RETURN_AUDIT_PROPERTIES, attributes);

		StringBuffer query=new StringBuffer();
		query.append("declare variable $customerId as xs:string external;\n");
		query.append("declare namespace tns='ld:RetailApplication/CustomerManagement/ProfileService';\n");
		query.append("tns:getCustomerByCustID($customerId)");
		com.bea.ld.ExternalVariables extVariables=new com.bea.ld.ExternalVariables();
		extVariables.setElement(new javax.xml.namespace.QName("customerId"), "CUSTOMER4", true);
		Object[] o=DSPControlFile.executeQuery(query.toString(), extVariables, reqConfig );
		outputString=dataObjectsToString(o);
		/** Dump out the audit information **/
		com.bea.ld.DataServiceAudit dsAudit = reqConfig.retrieveDataServiceAudit();
		if (dsAudit != null) {
			List l = dsAudit.getAllRecords();
			for (Iterator it = l.iterator(); it.hasNext();) {
				com.bea.ld.DSPAuditRecord auditRec = (com.bea.ld.DSPAuditRecord) it.next();
				Map propMap = auditRec.getAuditProperties();
				for (Iterator pit = propMap.keySet().iterator(); pit
						.hasNext();) {
					String key = (String) pit.next();
					outputString=outputString + "Audit Information: " + key + " = "
							+ propMap.get(key)+"\n";
				}
			}
		}

		
		Forward forward = new Forward("success");
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward useSetClassloader() {
		classloaderType=ClassloaderType.currentthread;
		Forward forward = begin();
		return forward;
	}

	@Jpf.Action(forwards = { @Jpf.Forward(name = "success", path = "index.jsp") })
	public Forward dontUseSetClassloader() {
		classloaderType=ClassloaderType.noclassloader;
		Forward forward = begin();
		return forward;
	}

	/**
	 * Callback that is invoked when this controller instance is created.
	 */
	@Override
	protected void onCreate() {
	}

	/**
	 * Callback that is invoked when this controller instance is destroyed.
	 */
	@Override
	protected void onDestroy(HttpSession session) {
	}
	
	public void out(String s){
		try{
			if(out instanceof javax.servlet.jsp.JspWriter)
				s=s.replace("&","&amp;").replace("<", "&lt;").replace(">", "&gt;");
			out.write(className+"/"+runningIn+"/"+clientType+"/"+classloaderType+" "+s+"\n");
			out.flush();
		}catch (Exception e){
			e.printStackTrace();
		}
	}

	public static InitialContext getInitialContext(String url, String username,
		String password) throws NamingException {
		Environment env = new Environment();
		env.setProviderUrl(url);
		env.setInitialContextFactory("weblogic.jndi.WLInitialContextFactory");
		env.setSecurityPrincipal(username);
		env.setSecurityCredentials(password);
		return new InitialContext(env.getInitialContext().getEnvironment());
	}

	String dataObjectToString(commonj.sdo.helper.XMLHelper xh, Object obj) {
		String theString=null;
		try {
			if(obj instanceof commonj.sdo.DataObject){
				commonj.sdo.DataObject dObj=(commonj.sdo.DataObject)obj;
				com.bea.sdo.PropertyXML element = ((com.bea.sdo.DataObjectXML) dObj)
						.getContainmentPropertyXML();
				String elementName = element.getName();
				String elementURI = element.getType().getURI();
				commonj.sdo.helper.XMLDocument xmlDocument = xh.createDocument(dObj, elementURI,
						elementName);
				StringWriter outputWriter = new StringWriter();
				xh.save(xmlDocument, outputWriter, null);
				theString=outputWriter.toString();
			} else if (obj instanceof Object[]){
				StringBuffer sb=new StringBuffer();
				Object[] objArray=(Object[]) obj;
				for(int i=0; i<objArray.length; i++)
					sb.append("    "+dataObjectToString(xh,objArray[i]));
				theString=sb.toString();
				return theString;
			} else {
				theString=obj.toString();
			}
			StackTraceElement[] stes=Thread.currentThread().getStackTrace();
			
			return stes[4].getMethodName()+"/"+runningIn+"/"+clientType+"/"+classloaderType+" "+theString.replace("&","&amp;").replace("<", "&lt;").replace(">", "&gt;");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	String dataObjectsToString(Object[] dObjs){
		StringBuffer sb=new StringBuffer();
		for(int i=0; i<dObjs.length; i++){
			sb.append(dataObjectToString(xh,dObjs[i])+"\n");
		}
		return sb.toString();
	}
	
	String dataObject2String(commonj.sdo.helper.XMLHelper xh, Object obj) {
		StringBuffer theString=new StringBuffer();
		try {

			if(obj instanceof commonj.sdo.DataObject){
				commonj.sdo.DataObject dObj=(commonj.sdo.DataObject)obj;
				com.bea.sdo.PropertyXML element = ((com.bea.sdo.DataObjectXML) dObj)
						.getContainmentPropertyXML();
				String elementName = element.getName();
				String elementURI = element.getType().getURI();
				commonj.sdo.helper.XMLDocument xmlDocument = xh.createDocument(dObj, elementURI,
						elementName);
				StringWriter outputWriter = new StringWriter();
				xh.save(xmlDocument, outputWriter, null);
				theString.append(outputWriter.toString());
			} else if (obj instanceof Object[]){
				Object[] objArray=(Object[])obj;
				for(int i=0;i<objArray.length; i++)
					theString.append(dataObject2String(xh,objArray[i]));
			} else {
				theString.append(obj.toString());
			}
			
			return theString.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}