package org.springframework.roo.shell.jline.osgi;

import static org.springframework.roo.support.util.AnsiEscapeCode.FG_CYAN;
import static org.springframework.roo.support.util.AnsiEscapeCode.FG_GREEN;
import static org.springframework.roo.support.util.AnsiEscapeCode.FG_MAGENTA;
import static org.springframework.roo.support.util.AnsiEscapeCode.REVERSE;
import static org.springframework.roo.support.util.AnsiEscapeCode.UNDERSCORE;
import static org.springframework.roo.support.util.AnsiEscapeCode.decorate;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.shell.ExecutionStrategy;
import org.springframework.roo.shell.Parser;
import org.springframework.roo.shell.jline.JLineShell;
import org.springframework.roo.support.osgi.OSGiUtils;
import org.springframework.roo.support.util.StringUtils;
import org.springframework.roo.url.stream.UrlInputStreamService;

/**
 * OSGi component launcher for {@link JLineShell}.
 *
 * @author Ben Alex
 * @since 1.1
 */
@Component(immediate = true)
@Service
public class JLineShellComponent extends JLineShell {
	
	// Constants
	private static final String LINE_SEPARATOR = System.getProperty("line.separator");
	
	// Fields
	@Reference private ExecutionStrategy executionStrategy;
	@Reference private Parser parser;
	@Reference private UrlInputStreamService urlInputStreamService;
	private ComponentContext context;

	protected void activate(ComponentContext context) {
		this.context = context;
		Thread thread = new Thread(this, "Spring Roo JLine Shell");
		thread.start();
	}

	protected void deactivate(ComponentContext context) {
		this.context = null;
		closeShell();
	}
	
	@Override
	protected Collection<URL> findResources(final String path) {
		// For an OSGi bundle search, we add the root prefix to the given path
		return OSGiUtils.findEntriesByPath(context.getBundleContext(), OSGiUtils.ROOT_PATH + path);
	}

	@Override
	protected ExecutionStrategy getExecutionStrategy() {
		return executionStrategy;
	}

	@Override
	protected Parser getParser() {
		return parser;
	}

	@Override
	public String getStartupNotifications() {
		return getLatestFavouriteTweet();
	}

	private String getLatestFavouriteTweet() {
		// Access Twitter's REST API
		String string = sendGetRequest("http://api.twitter.com/1/favorites.json", "id=SpringRoo&count=1");
		if (StringUtils.hasText(string)) {
			// Parse the returned JSON. This is a once off operation so we can used JSONValue.parse without penalty
			JSONArray object = (JSONArray) JSONValue.parse(string);
			JSONObject jsonObject = (JSONObject) object.get(0);
			String tweet = (String) jsonObject.get("text");
			// We only want one line
			tweet = tweet.replaceAll(LINE_SEPARATOR, " ");
			List<String> words = Arrays.asList(tweet.split(" "));
			StringBuilder sb = new StringBuilder();
			// Add in Roo's twitter account to give context to the notification
			sb.append(decorate("@SpringRoo", REVERSE));
			sb.append(" ");
			// We want to colourise certain words. The codes used here should be moved to a ShellUtils and include a few helper methods
			// This is a basic attempt at pattern identification, it should be adequate in most cases although may be incorrect for URLs.
			// For example url.com/ttym: is valid by may mean "url.com/ttym" + ":"
			for (String word : words) {
				if (word.startsWith("http://") || word.startsWith("https://")) {
					// It's a URL
					sb.append(decorate(word, FG_GREEN, UNDERSCORE));
				} else if (word.startsWith("@")) {
					// It's a Twitter username
					sb.append(decorate(word, FG_MAGENTA));
				} else if (word.startsWith("#")) {
					// It's a Twitter hash tag
					sb.append(decorate(word, FG_CYAN));
				} else {
					// All else default
					sb.append(word);
				}
				// Add back separator
				sb.append(" ");
			}
			return sb.toString();
		}
		return null;
	}

	// TODO: This should probably be moved to a HTTP service of some sort - JTT 29/08/11
	private String sendGetRequest(String endpoint, String requestParameters) {
		String result = null;
		if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
			// Send a GET request to the servlet
			try {
				// Send data
				String urlStr = endpoint;
				if (requestParameters != null && requestParameters.length() > 0) {
					urlStr += "?" + requestParameters;
				}
				URL url = new URL(urlStr);
				InputStream inputStream = urlInputStreamService.openConnection(url);
				// Get the response
				BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream));
				StringBuilder sb = new StringBuilder();
				String line;
				while ((line = rd.readLine()) != null) {
					sb.append(line);
				}
				rd.close();
				result = sb.toString();
			} catch (Exception ignored) {}
		}
		return result;
	}
}
@@ -693,16 +693,41 @@
 il.List;
+%0Aimport java.util.Random;
 %0A%0Aimport
@@ -2786,17 +2786,17 @@
 o&count=
-1
+5
 %22);%0A%09%09if
@@ -3001,57 +3001,239 @@
 %0A%09%09%09
-JSONObject jsonObject = (JSONObject) object.get(0
+int index = 0;%0A%09%09%09if (object.size() %3E 4) %7B%0A%09%09%09%09index = new Random().nextInt(5);%0A%09%09%09%7D%0A%09%09%09JSONObject jsonObject = (JSONObject) object.get(index);%0A%09%09%09String screenName = (String) ((JSONObject) jsonObject.get(%22user%22)).get(%22screen_name%22
 );%0A%09
@@ -3555,25 +3555,35 @@
 orate(%22@
-SpringRoo
+%22 + screenName + %22:
 %22, REVER

Add the ability to display notification upon startup in the Roo shell - randomly selects one of the last five favourite tweets, displays twitter screen name