using System;
using System.IO;
using System.Text;
using Plumtree.Remote.PRC;
using Plumtree.Remote.PRC.Content;
using Plumtree.Remote.PRC.Content.DataEntryTemplate;
using Plumtree.Remote.PRC.Content.Folder;
using Plumtree.Remote.PRC.Content.Item;
using Plumtree.Remote.PRC.Content.PresentationTemplate;
using Plumtree.Remote.PRC.Content.Property;
using Plumtree.Remote.PRC.Content.SelectionList;
using Plumtree.Remote.PRC.Content.Security;

namespace ContentItemCommandLineExample
{
	/// <summary>
	/// Command-line example of Content api
	/// </summary>
	/// <remarks>
	///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.
	///<para/>
	///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
	/// </remarks>
	class ContentExample
	{
		/// <summary>
		/// Runs through the high-level logic of importing records
		/// into Content Server.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			Console.WriteLine("Started Sample Application.");
			// Step 1:  Get an EDK session and Content Server factory.
			IRemoteSession session = EstablishSession();
			IContentFactory contentFactory = session.GetContentFactory();
			Console.WriteLine("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);
			Console.WriteLine("Step 2 - Folder retrieved with name: " + folder.Name);
		
            // 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);
            Console.WriteLine("Step 3 - Folder security updated with name: " + folder.Name);

			// 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);
			Console.WriteLine("Step 4 - Data Entry Template retrieved with name: " + det.Name);

			// 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);
			Console.WriteLine("Step 5 - Presentation Template retrieved with name: " + pt.Name);

			// Step 6:  Create content items.
			//  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);
			Console.WriteLine("Step 6 - Content Item created with name: " + ci.Name);

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

			// 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);
			Console.WriteLine("Step 7 - Folder deleted");

			Console.WriteLine("Finished Sample Application.");
		}
	
		/// <summary>
		/// Creates an EDK session. Change this to reference your SOAP endpoint.
		/// </summary>
		private static IRemoteSession EstablishSession() 
		{
			// Change the values below to match your configuration.
			Uri endpointURL = new Uri("http://localhost/ptapi/services/QueryInterfaceAPI");
			string username = "Administrator";
			string password = "";
		
			// Create a remote API session.
			IRemoteSession remoteSession = RemoteSessionFactory.GetExplicitLoginContext(endpointURL, username, password);

			return remoteSession;
		}
	
		/// <summary>
		/// Gets the Content Server folder used to store all 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.
		/// </summary>
		private static IFolder RetrieveContentFolder(IContentFactory factory) 
		{
			// 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, "C# Example - Support Incidents");
			subFolder.Store();

			return subFolder;
		}

	       /**
		 * 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)
		{
			//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
			Console.WriteLine("Printing ACL for folder " + folder.Name);
			Console.WriteLine(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
				Console.WriteLine("---------------------------------------------------------");
				Console.Write("ObjectID for this FolderACLEntry " + aclEntry.GetObjectID());
				Console.Write("MemberType for this FolderACLEntry " + aclEntry.GetMemberType());
				Console.WriteLine("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, RoleTypes.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, RoleTypes.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
			Console.WriteLine("Printing ACL for folder " + folder.Name);
			Console.WriteLine(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
				Console.WriteLine("---------------------------------------------------------");
				Console.Write("ObjectID for this FolderACLEntry " + aclEntry.GetObjectID());
				Console.Write("MemberType for this FolderACLEntry " + aclEntry.GetMemberType());
				Console.WriteLine("RoleType for this FolderACLEntry " + aclEntry.GetRoleType());
			}

			return folder;
		}

		/// <summary>
		/// 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 for an existing Data Entry Template.																										 * existing DET.
		/// </summary>
		private static IDataEntryTemplate RetrieveDET(IContentFactory factory, IFolder folder)
		{
			//
			// 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 double 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;
		}

		/// <summary>
		/// 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.
		/// </summary>
		private static IPresentationTemplate RetrievePT(IContentFactory factory, IDataEntryTemplate det)
		{
			//
			// 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();
	
		
			// Create a PT.
			StringBuilder templateBuffer = new StringBuilder();
			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");


			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.TemplateText);
			if(errorsInText.Length != 0)
			{
				Console.WriteLine("Validate Template Text returned the following errors");
				for(int i = 0; i < errorsInText.Length; i++)
				{
					Console.WriteLine("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;
		}

		/// <summary>
		/// Creates a content item representing a single support
		/// incident.
		/// </summary>
		private static IContentItem CreateSupportIncident(IContentFactory factory, IDataEntryTemplate det, IPresentationTemplate pt) 
		{
			//
			// 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],  DateTime.Now);
		
			// 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, you must have your string 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
			//FileStream log = new FileStream("C:\\uploads\\WidgetBroken.log", FileMode.Open);
			//incident.SetFilePropertyValue(props[8], "WidgetBroken.log", log);

			// Screen shot.
			//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
			//FileStream screenShot = new FileStream("C:\\uploads\\WidgetBroken.gif", FileMode.Open);
			//incident.SetImagePropertyValue(props[9], "WidgetBroken.gif", screenShot);

			// 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;
		}
	
	}
}
