public abstract class AbstractChannel implements IChannel, IChannelInternal {

	//
	// IChannel
	//

	private String _id;

	public String getChannelId() {
		return _id;
	}

	private String _description;

	public String getChannelData(String key, String... params) {
		switch (key) {
		case "channel.description":
			return _description;
		default:
			return null;
		}
	}

	public IChannelItemDetails getChannelItemDetails(String itemLabel,
			long itemOrdinal) {
		return null;
	}

	//
	// IChannelInternal
	//

	private IChannelService _channelService;

	public IChannelService getChannelService() {
		return _channelService;
	}

	public final void init(String channelId, IChannelService channelService,
			String channelDescription) {
		_id = channelId;
		_description = channelDescription;
		_channelService = channelService;
	}

	public void init() {
	}

	public void fini() {
	}

	public boolean channelSecurity(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		return true;
	}

	public void channelHttp(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		switch (request.getMethod()) {
		case "GET":
			channelHttpGet(request, response);
			break;
		case "POST":
			channelHttpPost(request, response);
			break;
		case "PUT":
			channelHttpPut(request, response);
			break;
		case "DELETE":
			channelHttpDelete(request, response);
			break;
		}
	}

	protected void channelHttpGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		channelHttpNotImplemented(request, response);
	}

	protected void channelHttpPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		channelHttpNotImplemented(request, response);
	}

	protected void channelHttpPut(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		channelHttpNotImplemented(request, response);
	}

	protected void channelHttpDelete(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		channelHttpNotImplemented(request, response);
	}

	private void channelHttpNotImplemented(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");

		PrintWriter writer = response.getWriter();

		String channelId = getChannelId();
		String thingName = getChannelData("thing", "name");
		writer.append("<html>\n<head>\n<title>");
		writer.append("fold: " + thingName + " / " + channelId);
		writer.append("</title>\n</head>\n<body>\n");

		writer.append("<p>");
		writer.append("Method " + request.getMethod() + " not implemented!");
		writer.append("</p>\n");

		writer.append("\n</body>\n</html>\n");
	}

	public final Properties getChannelConfigProperties(
			String propertiesFilePrefix) {
		String channelConfigFilePath = FoldUtil.getFoldConfigDir()
				+ "/channel/" + getChannelId() + "/" + propertiesFilePrefix
				+ ".properties";
		return FoldUtil.loadPropertiesFile(channelConfigFilePath);
	}

	public final IProject getChannelProject() {
		try {
			IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace()
					.getRoot();
			IProject project = workspaceRoot.getProject(getChannelId());
			boolean workspaceStateChange = false;

			if (!project.exists()) {
				workspaceStateChange = true;
				project.create(null);
			}

			if (!project.isOpen()) {
				workspaceStateChange = true;
				project.open(null);
			}

			if (workspaceStateChange) {
				workspaceRoot.getWorkspace().save(true, null);
			}

			return project;
		} catch (CoreException ex) {
			ex.printStackTrace();
		}
		return null;
	}

	private long _channelNodeId = -1;

	public final long getChannelNodeId() {
		if (_channelNodeId == -1) {
			INeo4jService neo4jService = Neo4jUtil.getNeo4jService();

			ICypher cypher = neo4jService
					.constructCypher("MERGE (channel:fold_Channel {fold_channelId : {channelId}}) RETURN ID(channel)");
			cypher.addParameter("channelId", getChannelId());
			neo4jService.invokeCypher(cypher);

			JsonValue jsonValue = cypher.getResultDataRow(0);
			_channelNodeId = jsonValue.asLong();
		}
		return _channelNodeId;
	}

} public interface IChannel {

	String getChannelId();

	String getChannelData(String key, String... params);

	IChannelItemDetails getChannelItemDetails(String itemLabel, long itemOrdinal);

	Class<? extends IChannel> getChannelInterface();

} public class ChatterItemDetails extends ChannelItemDetails {
	public ChatterItemDetails(ChatterChannel channel) {
		super(channel, "Chatter");
	}

	public String getItemKind() {
		return getCategory();
	}

	public long getTimestamp() {
		return getJson().getLong("Chatter_time", Long.MIN_VALUE);
	}

	public String getUrlPath() {
		return "/fold/chatter/" + getOrdinal();
	}

	public String getCategory() {
		return getJson().getString("Chatter_category", null);
	}

	public String getMessage() {
		return getJson().getString("Chatter_message", null);
	}

} public interface IChatterChannel extends IChannel {

	long createChatterItem(String message, String category, JsonObject data);

	long getLatestChatterOrdinal();

	ChatterItemDetails getChatterItemDetails(long ordinal);

} public interface ITimesChannel extends IChannel {

	long getEpochNodeId();

	long getMinuteNodeId(long timeMillis, boolean createIfAbsent);

	void createTimesRef(long timeMillis, long refNodeId);

	long[] getTimesRefNodeIds(long timeMillis, String refNodeLabel);

	long[] getTimesRefNodeIds(long timeMillis, String refNodeLabel,
			String refNodeKey, String refNodeValue);

	JsonObject[] getTimesRefNodes(long timeMillis, String refNodeLabel,
			String refNodeKey, String refNodeValue);

} public interface IChannelItemDetails extends ISketch {

	String getItemLabel();

	String getItemKind();

	long getTimestamp();

	long getOrdinal();

	JsonObject getJson();

	String getUrlPath();

	String[] getDataLines();
} public abstract class ChannelHeaderFooterHtml extends AbstractChannelHtmlSketch {

	public ChannelHeaderFooterHtml(IChannelInternal channel) {
		super(channel);
	}

	public void composeHtmlResponse(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");
		String thingName = getChannel().getChannelService().getChannelData(
				"thing", "name");

		HtmlComposer html = new HtmlComposer(response.getWriter());
		html.html_head("fold: " + thingName + " / "
				+ getChannel().getChannelId());

		composeHtmlResponseBody(request, response, html);

		html.html_body(false);
	}

	protected abstract void composeHtmlResponseBody(HttpServletRequest request,
			HttpServletResponse response, HtmlComposer html)
			throws ServletException, IOException;
} public class ChannelItemNode extends OrdinalNode {

	private String _itemLabel;

	public ChannelItemNode(IChannelInternal channel, String itemLabel) {
		super(channel.getChannelNodeId(), channel.getChannelId() + "_"
				+ itemLabel);
		_itemLabel = itemLabel;
	}

	public String getItemLabel() {
		return _itemLabel;
	}

} public class MultiPropertyAccessNode extends AbstractNodeSketch {

	private String _propertyNamePrefix;

	private ICypher _cypher;
	private StringBuilder _cypherStatement;
	private boolean _firstProperty;

	public MultiPropertyAccessNode(long nodeId) {
		this(nodeId, "");
	}

	public MultiPropertyAccessNode(long nodeId, String propertyNamePrefix) {
		_nodeId = nodeId;
		_propertyNamePrefix = propertyNamePrefix == null ? ""
				: propertyNamePrefix;
		reset();
	}

	public void reset() {
		INeo4jService neo4jService = getNeo4jService();
		_cypher = neo4jService.constructCypher("...placeholder...");
		_cypherStatement = new StringBuilder(
				"MATCH node WHERE id(node)={nodeId} SET ");
		_firstProperty = true;
	}

	public JsonObject getProperties() {
		INeo4jService neo4jService = getNeo4jService();
		String cypherText = "MATCH node" //
				+ " WHERE id(node)={nodeId}" //
				+ " RETURN node";

		ICypher cypher = neo4jService.constructCypher(cypherText);
		cypher.addParameter("nodeId", getNodeId());
		neo4jService.invokeCypher(cypher);
		JsonValue jsonValue = cypher.getResultDataRow(0);
		if ((jsonValue == null) || (!jsonValue.isObject()))
			return null;
		else
			return jsonValue.asObject();
	}

	private void addCypherSet(String name) {
		if (_firstProperty)
			_firstProperty = false;
		else
			_cypherStatement.append(",");

		_cypherStatement.append("node.`" + _propertyNamePrefix + name + "`={"
				+ name + "}");
	}

	public void addProperty(String name, JsonValue value) {
		addCypherSet(name);
		_cypher.addParameter(name, value);
	}

	public void addProperty(String name, int value) {
		addCypherSet(name);
		_cypher.addParameter(name, value);
	}

	public void addProperty(String name, long value) {
		addCypherSet(name);
		_cypher.addParameter(name, value);
	}

	public void addProperty(String name, float value) {
		addCypherSet(name);
		_cypher.addParameter(name, value);
	}

	public void addProperty(String name, double value) {
		addCypherSet(name);
		_cypher.addParameter(name, value);
	}

	public void addProperty(String name, boolean value) {
		addCypherSet(name);
		_cypher.addParameter(name, value);
	}

	public void addProperty(String name, String value) {
		addCypherSet(name);
		_cypher.addParameter(name, value);
	}

	public void setProperties() {
		INeo4jService neo4jService = getNeo4jService();
		_cypher.addParameter("nodeId", getNodeId());
		_cypher.setStatementText(_cypherStatement.toString());
		neo4jService.invokeCypher(_cypher);
	}
} public class HtmlComposer {

	private StringBuilder _builder;
	private PrintWriter _writer;

	public HtmlComposer(PrintWriter writer) {
		_writer = writer;
		_builder = new StringBuilder();
	}

	public String A(String href, String linkText) {
		_builder.setLength(0);
		_builder.append("<a href='");
		_builder.append(href);
		_builder.append("'>");
		_builder.append(linkText);
		_builder.append("</a>");
		return _builder.toString();
	}

	public void a(String href, String linkText) {
		_writer.print("<a href='");
		_writer.print(href);
		_writer.print("'>");
		_writer.print(linkText);
		_writer.println("</a>");
	}

	public void b(String text) {
		simpleTag("b", text);
	}

	public void br() {
		_writer.println("<br>");
	}

	public void button(String type, String text) {
		_writer.print("<button type='");
		_writer.print(type);
		_writer.print("'>");
		_writer.print(text);
		_writer.print("</button>");
	}

	public void code(String text) {
		simpleTag("code", text);
	}

	public void dd(String text) {
		simpleTag("dd", text);
	}

	public void div() {
		div(true);
	}

	public void div(boolean startTag) {
		simpleTag("div", startTag);
	}

	public void dl() {
		dl(true);
	}

	public void dl(boolean startTag) {
		simpleTag("dl", startTag);
	}

	public void dt(String text) {
		simpleTag("dt", text);
	}

	public void em(String text) {
		simpleTag("em", text);
	}

	public void form() {
		form(false);
	}

	public void form(boolean startTag) {
		simpleTag("form", startTag);
	}

	public void h(int level, String text) {
		if (level < 1)
			level = 1;
		else if (level > 6)
			level = 6;
		_writer.print("<h");
		_writer.print(level);
		_writer.print(">");
		_writer.print(text);
		_writer.print("</h");
		_writer.print(level);
		_writer.println(">");
	}

	public void html_head(String title) {
		_writer.println("<html>");
		_writer.println("<head>");
		_writer.print("<title>");
		_writer.print(title);
		_writer.println("</title>");
		_writer.println("</head>");
		_writer.println("<body>");
	}

	public void html_body(boolean startTag) {
		if (!startTag) {
			_writer.println("</body>");
			_writer.println("</html>");
		}
	}

	public void i(String text) {
		simpleTag("i", text);
	}

	public void img(String src, String alt) {
		_writer.print("<img src='");
		_writer.print(src);
		_writer.print("' alt='");
		_writer.print(alt);
		_writer.print("'>");
	}

	public void input(String type, String name) {
		_writer.print("<input type='");
		_writer.print(type);
		_writer.print("' name='");
		_writer.print(name);
		_writer.println("'>");
	}

	public void li(String text) {
		simpleTag("li", text);
	}

	public void object(String data, String type) {
		_writer.print("<object data='");
		_writer.print(data);
		_writer.print("' type='");
		_writer.print(type);
		_writer.print("'></object>");
	}

	public void ol() {
		ol(true);
	}

	public void ol(boolean startTag) {
		simpleTag("ol", startTag);
	}

	public void p() {
		p(true);
	}

	public void p(boolean startTag) {
		simpleTag("p", startTag);
	}

	public void p(String text) {
		simpleTag("p", text);
	}

	public void pre(String text) {
		simpleTag("pre", text);
	}

	public void span(String text) {
		simpleTag("span", text);
	}

	public void strong(String text) {
		simpleTag("strong", text);
	}

	public void table() {
		table(true);
	}

	public void table(boolean startTag) {
		simpleTag("table", startTag);
	}

	public void text(String text) {
		_writer.print(text);
	}

	public void td(String text) {
		simpleTag("td", text);
	}

	public void th(String text) {
		simpleTag("th", text);
	}

	public void tr(boolean startTag) {
		simpleTag("tr", startTag);
	}

	public void tr(String... tableCells) {
		tr(false, tableCells);
	}

	public void tr(boolean isHeader, String... tableCells) {
		_writer.print("<tr>");
		for (String tableCell : tableCells) {
			if (isHeader)
				_writer.print("<th>");
			else
				_writer.print("<td>");
			_writer.print(tableCell);
			if (isHeader)
				_writer.print("</th>");
			else
				_writer.print("</td>");
		}
		_writer.println("</tr>");
	}

	public void ul() {
		ul(true);
	}

	public void ul(boolean startTag) {
		simpleTag("ul", startTag);
	}

	//
	//

	private void simpleTag(String tag, String text) {
		_writer.print("<");
		_writer.print(tag);
		_writer.print(">");
		_writer.print(text);
		_writer.print("</");
		_writer.print(tag);
		_writer.println(">");
	}

	private void simpleTag(String tag, boolean startTag) {
		if (startTag) {
			_writer.print("<");
			_writer.print(tag);
			_writer.println(">");
		} else {
			_writer.print("</");
			_writer.print(tag);
			_writer.println(">");
		}
	}

}
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
import com.eclipsesource.json.WriterConfig;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.locosoft.fold.channel.AbstractChannel;
import net.locosoft.fold.channel.IChannel;
import net.locosoft.fold.channel.chatter.ChatterItemDetails;
import net.locosoft.fold.channel.chatter.IChatterChannel;
import net.locosoft.fold.channel.times.ITimesChannel;
import net.locosoft.fold.sketch.IChannelItemDetails;
import net.locosoft.fold.sketch.pad.html.ChannelHeaderFooterHtml;
import net.locosoft.fold.sketch.pad.neo4j.ChannelItemNode;
import net.locosoft.fold.sketch.pad.neo4j.MultiPropertyAccessNode;
import net.locosoft.fold.util.HtmlComposer;
import org.eclipse.core.runtime.Path;
/*****************************************************************************
 * Copyright (c) 2015 Chris J Daly (github user cjdaly)
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   cjdaly - initial API and implementation
 ****************************************************************************/

package net.locosoft.fold.channel.chatter.internal;






public class ChatterChannel extends AbstractChannel implements IChatterChannel {

	public Class<? extends IChannel> getChannelInterface() {
		return IChatterChannel.class;
	}

	public long createChatterItem(String message, String category,
			JsonObject data) {
		if (message == null)
			return -1;
		if (category == null)
			category = "";

		ChannelItemNode chatterItemNode = new ChannelItemNode(this, "Chatter");
		long chatterNodeId = chatterItemNode.nextOrdinalNodeId();
		long chatterNodeOrdinal = chatterItemNode
				.getOrdinalIndex(chatterNodeId);

		MultiPropertyAccessNode chatterNode = new MultiPropertyAccessNode(