import java.net.URL;
import java.util.Date;

import com.plumtree.remote.prc.IRemoteSession;
import com.plumtree.remote.prc.RemoteSessionFactory;
import com.plumtree.remote.prc.content.IContentFactory;
import com.plumtree.remote.prc.content.dataentrytemplate.IDataEntryTemplate;
import com.plumtree.remote.prc.content.dataentrytemplate.IDataEntryTemplateManager;
import com.plumtree.remote.prc.content.folder.IFolder;
import com.plumtree.remote.prc.content.folder.IFolderManager;
import com.plumtree.remote.prc.content.item.IContentItem;
import com.plumtree.remote.prc.content.item.IContentItemManager;
import com.plumtree.remote.prc.content.presentationtemplate.IPresentationTemplate;
import com.plumtree.remote.prc.content.presentationtemplate.IPresentationTemplateManager;
import com.plumtree.remote.prc.content.property.IBaseProperty;
import com.plumtree.remote.prc.content.property.IBooleanProperty;
import com.plumtree.remote.prc.content.property.IDateProperty;
import com.plumtree.remote.prc.content.property.IDoubleProperty;
import com.plumtree.remote.prc.content.property.IFileProperty;
import com.plumtree.remote.prc.content.property.IImageProperty;
import com.plumtree.remote.prc.content.property.IIntegerProperty;
import com.plumtree.remote.prc.content.property.IItemReferenceProperty;
import com.plumtree.remote.prc.content.property.IPropertyManager;
import com.plumtree.remote.prc.content.property.ISelectionListProperty;
import com.plumtree.remote.prc.content.property.ITextBlockProperty;
import com.plumtree.remote.prc.content.property.ITextLineProperty;
import com.plumtree.remote.prc.content.security.IFolderACL;
import com.plumtree.remote.prc.content.security.IFolderACLEntry;
import com.plumtree.remote.prc.content.security.RoleType;
import com.plumtree.remote.prc.content.selectionlist.ISelectionList;
import com.plumtree.remote.prc.content.selectionlist.ISelectionListManager;

/**
 * This sample demonstrates all of the basic Content Server API
 * objects. It can be run from the command line, creates all of
 * its data, and cleans up after itself when it is done.
 * <p>
 * This is an example of a programatically creating content items
 * (records in the Content Server). The use case is a business
 * process where something triggers a customer support incident.
 * This creates a content item for the incident that can be viewed
 * from the portal in a support incident portlet.
 *
 * Before running this sample
 * 1) Verify the endpointURL and username and password are correct in establishSession()
 * 2) Set any break points to observe the sample as it runs
 * 3) Comment out the folderManager.removeFolder(folder); if you want to keep the created items after the sample has run
 */
public class ContentItemCommandLineExample
{

	/**
	 * Runs through the high-level logic of importing records
	 * into Content Server.
	 */
	public static void main(String[] args) throws Exception
	{
	    System.out.println("Started sample application");
		// Step 1:  Get an EDK session and Content Server factory.
		IRemoteSession session = establishSession();
		IContentFactory contentFactory = session.getContentFactory();
		System.out.println("Step 1 - Session Established and Content Factory Created");

		// Step 2:  Get a Content Server folder.
		//  All Content Server objects are stored in folders. Since
		//  they are necessary for creating or querying objects, the
		//  first real step is to get your application's folder(s).
		IFolder folder = retrieveContentFolder(contentFactory);
		System.out.println("Step 2 - Folder retrieved with name: " + folder.getName());

		// Step 3:  Set security on the Content Server folder
		// All Content Server folders have access control lists
		// or ACLs associated with them.  This step adds a user
		// and a group to this folder's ACL.
		folder = updateContentFolderSecurity(folder);
		System.out.println("Step 3 - Folder security updated with name: " + folder.getName());

		// Step 4:  Get the Data Entry Template (DET).
		//  A DET is used when creating any collection of records.
		//  It defines the fields within each record and logically
		//  groups them together. A DET is analogous to creating
		//  a new database table. In this example the DET represents
		//  the fields in each customer support incident.
		IDataEntryTemplate det = retrieveDET(contentFactory, folder);
		System.out.println("Step 4 - Data Entry Template retrieved with name: " + det.getName());

		// Step 5:  Get the Presentation Template (PT).
		//  The PT describes how each record within a collection is
		//  displayed. For each collection of records, there is
		//  exactly one DET and PT. Both are needed to publish
		//  individual records (content items).
		IPresentationTemplate pt = retrievePT(contentFactory, det);
		System.out.println("Step 5 - Presentation Template retrieved with name: " + pt.getName());

		// Step 6:  Create content item.
		//  Each support incident is a new content item. Content items
		//  are records and analogous to rows in a database table.
		//
		//  In a real application, we would actually want receive events
		//  for when new support incidents are registered from some
		//  other system such as Siebel. This would probably be done
		//  as a loop, but for this example we will create a single
		//  record.
		IContentItem ci = createSupportIncident(contentFactory, det, pt);
		System.out.println("Step 6 - Content Item created with name: " + ci.getName());

		System.out.println("\nThe Content Item has been created. \nYou may go to the Content Server Manager to observe the objects that have been created");
		System.out.println("When you are done, press any key to remove the created items and finish the sample");
		System.in.read();

		// Step 7:  Cleanup.
		//  Normally an application would not erase all of its data,
		//  but since this is a sample it should clean up after itself.

		//  Comment out these lines if you want to see all of the
		//  content that is created without setting break points.
		IFolderManager folderManager = contentFactory.getFolderManager();
		folderManager.removeFolder(folder);
		System.out.println("Step 7 - Folder deleted");

		System.out.println("Finished sample application");
	}

	/**
	 * Creates an EDK session. Change this to reference your SOAP endpoint.
	 */
	private static IRemoteSession establishSession() throws Exception
	{
		// Change the values below to match your configuration.
		URL endpointURL = new URL("http://localhost/ptapi/services/QueryInterfaceAPI");
		String username = "Administrator";
		String password = "";

		// Create a remote API session.
		IRemoteSession remoteSession = RemoteSessionFactory.getExplicitLoginContext(endpointURL, username, password);
		return remoteSession;
	}

	/**
	 * Gets the Content Server ACL for the folder used to store the Content
	 * Server objects for our application.
	 * <p>
	 * In this sample, we will display the current ACL on the folder and will add
	 * a new user and group entry for this folder.
	 */
	private static IFolder updateContentFolderSecurity(IFolder folder) throws Exception
	{
		//get the existing ACL associated with this folder
		IFolderACL folderACL = folder.getFolderACL();

		// get the entries off of this ACL
		IFolderACLEntry [] entries = folderACL.getEntries();

		// loop through the entries and print out the values of each entry
		System.out.println("Printing ACL for folder " + folder.getName());
		System.out.println(entries.length + " entries found in this ACL");
		for (int i = 0; i < entries.length; i++) {
			// get the individual entry
			IFolderACLEntry aclEntry = entries[i];

			// print out its details
			System.out.println("---------------------------------------------------------");
			System.out.print("ObjectID for this FolderACLEntry " + aclEntry.getObjectID());
			System.out.print("MemberType for this FolderACLEntry " + aclEntry.getMemberType());
			System.out.println("RoleType for this FolderACLEntry " + aclEntry.getRoleType());
		}

		// now add a new entry to this acl for the portal Guest user
		// the guest user's object id is 2.
		folderACL.addUserEntry(2, RoleType.EDITOR);

		// now add a new entry to this acl for the portal Administrator's group
		// the portal Administrator's group's object id is 1.
		folderACL.addGroupEntry(1, RoleType.ADMINISTRATOR);

		// store this acl to persist the changes back to the server
		folderACL.store();

		// loop through the entries and print out the values of each entry
		System.out.println("Printing ACL for folder " + folder.getName());
		System.out.println(entries.length + " entries found in this ACL");
		for (int i = 0; i < entries.length; i++) {
			// get the individual entry
			IFolderACLEntry aclEntry = entries[i];

			// print out its details
			System.out.println("---------------------------------------------------------");
			System.out.print("ObjectID for this FolderACLEntry " + aclEntry.getObjectID());
			System.out.print("MemberType for this FolderACLEntry " + aclEntry.getMemberType());
			System.out.println("RoleType for this FolderACLEntry " + aclEntry.getRoleType());
		}

		return folder;
	}

	/**
	 * Gets the Content Server folder used to store the Content
	 * Server objects for our application.
	 * <p>
	 * In this sample, we will create a new folder. In your
	 * real application you would likely have created the folder
	 * already and will need to query for it here.
	 */
	private static IFolder retrieveContentFolder(IContentFactory factory) throws Exception
	{
		// Get a folder manager for working with Content Server folders.
		IFolderManager folderManager = factory.getFolderManager();

		//If we were looking for an existing folder by path we could
		//use the following method
		//IFolder subFolder = folderManager.getFolderByPath("/folder1/folder2");

		//Instead, we will create our own folder for the sample

		// Get a reference to the root folder. It always exists.
		IFolder rootFolder = folderManager.getRootFolder();

		// Create a new folder
		IFolder subFolder = folderManager.createFolder(rootFolder, "Java Example - Support Incidents");
		subFolder.store();

		return subFolder;
	}

	/**
	 * Gets the DET that defines what fields are present in each
	 * customer support incident.
	 * <p>
	 * In this sample, we will create a new DET. In your real
	 * application, this method would probably query an already
	 * existing DET.
	 */
	private static IDataEntryTemplate retrieveDET(IContentFactory factory, IFolder folder) throws Exception
	{
		//
		// A Data Entry Template object is a collection of
		// property objects. Each property object represents
		// a field in the records associated with the DET.
		//
		// This sample uses all of the classes of properties
		// available in Content Server. Each customer support
		// incidents will have:
		//   (integer)         Incident ID
		//   (boolean)         If the incident has been resolved
		//   (float)           Incident severity rating
		//   (date)            Date the incident was opened
		//   (text line)       Customer name
		//   (item reference)  Link to other content item representing the customer
		//   (selection list)  The product the incident was reported in
		//   (text block)      Reported problem
		//   (file)            Logs of problem
		//   (image)           Screen shot of problem
		//

		// Get manager objects needed for creating a DET.
		IDataEntryTemplateManager detManager = factory.getDataEntryTemplateManager();
		IPropertyManager propertyManager = factory.getPropertyManager();
		ISelectionListManager slManager = factory.getSelectionListManager();

		// Create a DET object.
		IDataEntryTemplate det = detManager.createDataEntryTemplate(folder, "Support Incident Data Entry Template");

		// Add an integer property.
		IIntegerProperty incident = propertyManager.createIntegerProperty("Incident ID", "The ticket number for this incident.");
		det.addProperty(incident);

		// Add a boolean property
		IBooleanProperty resolved = propertyManager.createBooleanProperty("Resolved", "True if the incident has been closed; false if it is still open.");
		det.addProperty(resolved);

		// Add a float property.
		IDoubleProperty severity = propertyManager.createDoubleProperty("Severity", "Percentage stating how severe the incident is.");
		det.addProperty(severity);

		// Add a date property.
		IDateProperty opened = propertyManager.createDateProperty("Date Opened", "The date and time the incident was reported.");
		det.addProperty(opened);

		// Add a text line property.
		//  Text lines are brief strings without newline characters.
		//  Use the text block property for storing longer strings.
		ITextLineProperty customerName = propertyManager.createTextLineProperty("Customer Name", "The name of the customer.");
		det.addProperty(customerName);

		// Add an item reference property.
		//  An item reference links to another content item. The
		//  content item does not have to be associated with the
		//  same DET. For example, we will link to a fictional
		//  content item representing the customer that is having
		//  the support problem; which would be associated with
		//  a DET representing customers.
		//
		//  Not shown is the item collection property. It is
		//  similar to the item reference property, but links to
		//  multiple content items.
		IItemReferenceProperty customerData = propertyManager.createItemReferenceProperty("Customer Information", "Links to information about the customer such as the contact and their phone number.");
		det.addProperty(customerData);

		// Add a selection list property.
		//  A selection list is a defined set of choices of which
		//  one may be selected. This can be visualized as a
		//  drop down box.
		String[] listValues = {"Portal", "Search Server", "Collaboration Server", "Content Server", "Analytics"};
		ISelectionList selectionList = slManager.createSelectionList(folder, "Products Selection List", listValues);
		selectionList.store();

		ISelectionListProperty products = propertyManager.createSelectionListProperty("Product", "The product which the support incident is opened against", selectionList);
		det.addProperty(products);

		// Add a text block property.
		//  Text block properties are used to store long strings
		//  that can span many lines. For short strings contained
		//  on only one line, use the text line property instead.
		ITextBlockProperty description = propertyManager.createTextBlockProperty("Incident Description", "A writeup summarizing the problem the customer is experiencing.");
		det.addProperty(description);

		// Add a file property.
		IFileProperty log = propertyManager.createFileProperty("Log File", "A log file taken while the problem occurred.");
		det.addProperty(log);

		// Add an image property.
		IImageProperty screenShot = propertyManager.createImageProperty("Screen Shot", "A screen shot of the problem.");
		det.addProperty(screenShot);

		// Actually store the DET and all the properties associated with it.
		det.store();

		return det;
	}

	/**
	 * Gets the PT that defines how to display customer support
	 * incident records.
	 * <p>
	 * In this sample, we will create a new PT. In your real
	 * application, this method would probably query an already
	 * existing PT.
	 */
	private static IPresentationTemplate retrievePT(IContentFactory factory, IDataEntryTemplate det) throws Exception
	{
		//
		// A Presentation Template object defines how content
		// items associated with a Data Entry Template should
		// be displayed. For content items to be displayed,
		// the must have a DET and PT associated with them
		// and be published.
		//

		// Get a PT manager object.
		IPresentationTemplateManager ptManager = factory.getPresentationTemplateManager();

		// The template text determines how a content item is displayed.
		// In this sample we create a template that displays all the information in a table
		StringBuffer templateBuffer = new StringBuffer("");
		templateBuffer.append("<table border='1'>\n")
		.append("<tr><td><b>Incident ID</b></td><td><pcs:value expr='Incident_ID'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Created By</b></td><td><pcs:value expr='createdBy'></pcs:value> on <pcs:value expr='created' format='MMMM d, yyyy'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Resolved</b></td><td><pcs:value expr='Resolved'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Severity</b></td><td><pcs:value expr='Severity'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Date Opened</b></td><td><pcs:value expr='Date_Opened' format='MMMM d, yyyy'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Customer Name</b></td><td><pcs:value expr='Customer_Name'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Customer Information</b></td><td><pcs:value expr='Customer_Information.name'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Product</b></td><td><pcs:value expr='Product'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Incident Description</b></td><td><pcs:value expr='Incident_Description'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Log File</b></td><td><pcs:value expr='Log_File.name'></pcs:value></td></tr>\n")
		.append("<tr><td><b>Screen Shot</b></td><td><pcs:value expr='Screen_Shot.name'></pcs:value></td></tr>\n")
		.append("</table>\n");

		// Create the presentation template with the template
		IPresentationTemplate pt = ptManager.createPresentationTemplate(det.getContainingFolder(), "Customer Support Incident Presentation Template", templateBuffer.toString());

		// Store the PT.
		pt.store();

		// Validate the template text before using it to publish items
		String[] errorsInText = ptManager.validateTemplateText(pt, pt.getTemplateText());
		if(errorsInText.length != 0)
		{
		    System.out.println("Validate Template Text returned the following errors");
		    for(int i = 0; i < errorsInText.length; i++)
		    {
		        System.out.println("error[" + i + "]: " + errorsInText[i]);
		    }
		}

		// Associate the PT with a DET.
		//  There is a one-to-one correspondance between Data Entry
		//  Templates and Presentation Templates. A PT must be attached
		//  to a DET in order for content items to be published (i.e.
		//  viewable).
		det.attachPresentationTemplate(pt);
		det.store();

		return pt;
	}

	/**
	 * Creates a content item representing a single support
	 * incident.
	 */
	private static IContentItem createSupportIncident(IContentFactory factory, IDataEntryTemplate det, IPresentationTemplate pt) throws Exception
	{
		//
		// Content items (CI) are associated with a single DET/PT
		// combination. There can be zero or more content
		// items associated with that pair. The DET defines
		// the fields in the content items while the PT
		// defines how to display them.
		//

		// Get a CI manager object.
		IContentItemManager ciManager = factory.getContentItemManager();

		// Create a new CI.
		IContentItem incident = ciManager.createContentItem(det.getContainingFolder(), "Incident Name", det);

		// Assign the fields of the CI.
		// Each field is defined by the DET corresponding to the CI.
		IBaseProperty[] props = det.getAllProperties();

		// Incident ID.
		incident.setIntegerPropertyValue(props[0], 123);

		// Resolved?
		incident.setBooleanPropertyValue(props[1], false);

		// Severity.
		incident.setDoublePropertyValue(props[2], 0.90 );

		// Date incident opened.
		incident.setDatePropertyValue(props[3], new Date());

		// Customer's name
		incident.setTextLinePropertyValue(props[4], "Customer X");

		// Link to another content item (CI) representing the customer's data.
		//  Assumes there was another content item in the same folder named
		//  with the customer's name. In reality this will return null since
		//  we never created it.
		//IContentItem customer = ciManager.getContentItem(det.getContainingFolder(), "Customer X");
		//incident.setItemReferencePropertyValue(props[5], customer);

		// Product name containing problem.
		//  When setting a selection list value, the passed in string should exactly
		//  match one of the values in the selection list.
		incident.setSelectionListPropertyValue(props[6], "Portal");

		// Incident description.
		incident.setTextBlockPropertyValue(props[7], "The widget is broken.\nThe widget is fixed in the latest version and the fix must be back ported.");

		// Log file.
		//Commented out because we don't automatically have a WidgetBroken.log to upload.
		//To test this property, change the file name to a valid file on your system and uncomment
		//FileInputStream log = new FileInputStream("C:\\WidgetBroken.log");
		//incident.setFilePropertyValue(props[8], "WidgetBroken.log", log);

		// Screen shot.
		//Commented out because we don't automatically have a WidgetBroken.gif to upload.
		//To test this property, change the file name to a valid file on your system and uncomment
		//FileInputStream screenShot = new FileInputStream("C:\\WidgetBroken.gif");
		//incident.setImagePropertyValue(props[9], "WidgetBroken.gif", screenShot);

		// Actually store the CI.
		ciManager.checkInItem(incident, "Automatically created support incident.");

		// Publish the CI.
		//  This will make it visible to end users. Simply checking in a content
		//  item is not enough to make it visible.
		ciManager.publishContentItem(incident);

		return incident;
	}

}
