/* $Id: ZidestoreConnection.java,v 1.1 2004/01/09 16:54:18 burkhard Exp $
 * Created on 07.05.2003 by sell
 *
 */
package de.skyrix.zsp.logic;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.swing.event.EventListenerList;

import de.skyrix.zsp.conf.ZSPConfig;
import de.skyrix.zsp.event.CacheEvent;
import de.skyrix.zsp.event.CacheListener;
import de.skyrix.zsp.logic.httpclient.HttpRequest;
import de.skyrix.zsp.logic.httpclient.HttpResponse;
import de.skyrix.zsp.logic.parser.PropfindResponseParser;

/**Verwaltet die Verbindungen zum Zidestore Server.
 * 
 * @author sell
 * @version 
 */
public class ZidestoreConnection {
	private boolean useBasicAuthentication = true;
	private EventListenerList listeners;
  private boolean walkEnabled = false;

	static long queries = 0;
	static long messages = 0;
	static long folders = 0;

	public ZidestoreConnection() {
		listeners = new EventListenerList();
	}

	public void addCacheListener(CacheListener listener) {
		listeners.add(CacheListener.class, listener);
	}

	public void removeCachelistener(CacheListener listener) {
		listeners.remove(CacheListener.class, listener);
	}

	private void callCacheListeners(DAVItem item) {
		if (listeners.getListenerCount(CacheListener.class) > 0) {
			Object[] lobj = listeners.getListenerList();

			for (int i = 0; i < lobj.length; i++) {
				if (lobj[i] instanceof CacheListener) {
					CacheEvent event = new CacheEvent(this, 100, item);
					((CacheListener) lobj[i]).collectionFound(event);
				}
			}
		}
	}

	public HttpRequest createRequest(String url, String method)
		throws MalformedURLException {
		HttpRequest request = null;
		try {
			request = new HttpRequest(url, method);
		}
		catch (MalformedURLException e) {
			request =
				new HttpRequest(ZSPConfig.getProperty("zidestore_url") + url, method);
		}
		request.setUseBasicAuthentication(useBasicAuthentication);
		request.setUserName(ZSPConfig.getProperty("zidestore_user"));
		request.setPassword(ZSPConfig.getProperty("zidestore_password"));
		request.setRequestProperty(
			"User-Agent",
			"neon/0.23.5 ZideLook-Codeon/1.0.0");
		request.setRequestProperty(
			"Host",
			request.getURL().getHost() + ":" + request.getURL().getPort());
		request.setRequestProperty("Connection", "TE");
		request.setRequestProperty("TE", "trailers");

		return request;
	}

	public ArrayList listFolderItems(String folder) throws IOException {
		HttpRequest request = createRequest(folder, "PROPFIND");
		request.setRequestProperty("Depth", "1");

		request.setData(ZidelookQueries.ZideLookFolderQuery2);

		HttpResponse response = sendData(request);

		//System.out.println("resp body = "+response.getBody());

		if (response != null) {
			PropfindResponseParser parser =
				new PropfindResponseParser(response.getBody());
			ArrayList aRet = parser.parseDocument();

			if (aRet != null) {
				Iterator itemIterator = aRet.iterator();
				while (itemIterator.hasNext()) {
					try {
						DAVItem item = (DAVItem) itemIterator.next();
						item.setProperty("resourcetype", "collection", "D", "DAV:");
					}
					catch (Exception e) {
					}
				}

				return aRet;
			}
		}

		return null;
	}

	public DAVItem getFolderAttribs(String folder) throws IOException, SocketException {
		HttpRequest request = createRequest(folder, "PROPFIND");
		request.setRequestProperty("Depth", "0");

		//System.out.println("folder = " + folder);

		request.setData(ZidelookQueries.allPropQuery);

		HttpResponse response = sendData(request);
		
    if (response != null) {
			//System.out.println("body = "+response.getBody());
			PropfindResponseParser parser =
				new PropfindResponseParser(response.getBody());
			try {
				DAVItem item = (DAVItem) parser.parseDocument().get(0);
				return item;
			}
			catch (Exception e) {
				//e.printStackTrace();
			}
		}

		return null;
	}

	public ArrayList getAttributes(String folder, String range)
		throws IOException {
		String folderWithRange = folder;
		if (range != null)
			folderWithRange += range;

		HttpRequest request = createRequest(folderWithRange, "PROPFIND");
		request.setRequestProperty("Depth", "0");

		request.setData(ZidelookQueries.allPropQuery);

		HttpResponse response = sendData(request);
		if (response != null) {
			PropfindResponseParser parser =
				new PropfindResponseParser(response.getBody());
			return parser.parseDocument();
		}

		return null;
	}

	public ArrayList getIDsAndVersions(String folder) throws IOException {

		if (folder == null)
			return null;

		String myFolder = folder;
		ArrayList aRet = null;
		if (!myFolder.endsWith("/"))
			myFolder += "/";

		if (!myFolder.startsWith("http")) {
			myFolder = ZSPConfig.getProperty("zidestore_url") + myFolder;
			//System.out.println("myFolder is now " + myFolder);
		}

		HttpRequest request = createRequest(myFolder + "getIDsAndVersions", "GET");

		//request.setData(ZidelookQueries.allPropQuery);

		HttpResponse response = sendData(request);
		if (response != null && response.getStatusCode() == 200) {
			String responseBody = response.getBody();
			if (responseBody != null && !responseBody.trim().equals("")) {
				aRet = new ArrayList();

				StringTokenizer tokenizer1 =
					new StringTokenizer(responseBody, "\n", false);
				while (tokenizer1.hasMoreTokens()) {
					StringTokenizer tokenizer2 =
						new StringTokenizer(tokenizer1.nextToken(), ":", false);
					try {
						aRet.add(
							new IdVersionPair(
								tokenizer2.nextToken(),
								Integer.parseInt(tokenizer2.nextToken())));
					}
					catch (Exception e) {
					}
				}
			}
		}

		return aRet;
	}

	public HttpResponse loopThrough(
		String uri,
		String method,
		Properties header,
		String body) {
		try {
			//System.out.println("loop through");
			HttpRequest request =
				createRequest(ZSPConfig.getProperty("zidestore_url") + uri, method);
			request.setRequestProperties(header);
			request.setData(body);

			return sendData(request);
		}
		catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	public HttpResponse sendData(HttpRequest request) throws IOException {
		if (request == null)
			return null;

		queries++;

		HttpResponse response = null;

		try {
			//System.out.println("Request is:\n" + request.getHeader() + "\n\n");

			Socket socket =
				new Socket(request.getURL().getHost(), request.getURL().getPort());
			socket.setKeepAlive(true);
			PrintWriter out = new PrintWriter(socket.getOutputStream());
			out.println(request.getHeader());
			out.println("");

			if (request.getData() != null)
				out.println(request.getData());

			out.flush();

			InputStream in = socket.getInputStream();

			response = new HttpResponse(in);

			if (response.getStatusCode() == 401) {
				if (!useBasicAuthentication) {
					request.setUseBasicAuthentication(true);
					return sendData(request);
				}
				else {
					System.err.println("Unable to authentificate.");
					Proxy.setOnline(false);
					return null;
				}
			}

			in.close();
			out.close();
		}
		catch (UnknownHostException e) {
			System.err.println("\nUnknown host.");
			Proxy.setOnline(false);
			throw e;
		}
		catch (ConnectException e) {
			System.err.println("\nUnable to connect to zidestore server.");
			Proxy.setOnline(false);
			throw e;
		}
		catch (IOException e) {
			System.err.println("\nUnable to connect to zidestore server.");
			Proxy.setOnline(false);
			throw e;
		}

		Proxy.setOnline(true);
		return response;
	}

	public ArrayList getItemAttributes(String rootFolder, List items)
		throws IOException {
		if (items == null || items.isEmpty())
			return null;

		ArrayList aRet = new ArrayList(items.size());
		Iterator itemIterator = items.iterator();
		String currentRange = "_range";
		ArrayList ranges = new ArrayList();
		int elementCounter = 0;

		while (itemIterator.hasNext()) {
			try {
				messages++;
				elementCounter++;

				IdVersionPair idVersionPair = (IdVersionPair) itemIterator.next();

				currentRange += "_" + idVersionPair.getID();

				if (elementCounter >= 64) {
					ranges.add(currentRange);
					currentRange = "_range";
					elementCounter = 0;
					//System.out.println("splitting");
				}
			}
			catch (Exception e) {
			}
		}
		if (!"_range".equals(currentRange))
			ranges.add(currentRange);

		Iterator rangeIterator = ranges.iterator();
		while (rangeIterator.hasNext()) {
			String dir = rootFolder;
			if (!rootFolder.endsWith("/"))
				dir += "/";
			ArrayList atts = getAttributes(dir + rangeIterator.next(), null);
			if (atts != null && !atts.isEmpty()) {
				aRet.addAll(atts);
			}
		}

		return aRet;
	}
  
  public void enableWalk(boolean enable) {
    walkEnabled = enable;
  }

	public void walkTroughFolders(String rootFolder) throws IOException {
		ArrayList davResponses = listFolderItems(rootFolder);
		if (davResponses != null) {
			Iterator davResponseIterator = davResponses.iterator();
			while (davResponseIterator.hasNext() && walkEnabled) {
				try {
					DAVItem davResponse = (DAVItem) davResponseIterator.next();
					if (davResponse.getLocation() != null
						&& !davResponse.getLocation().equals(rootFolder)) {
						if (davResponse.isFolder()) {
							folders++;
              
							davResponse.setAll(getFolderAttribs(davResponse.getLocation()));

							//Listener aufrufen
							callCacheListeners(davResponse);

							if (davResponse.hasSubfolders()) {
								walkTroughFolders(davResponse.getLocation());
							}

						}
					}
				}
				catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	public long getQueryCount() {
		return queries;
	}

	public long getMessageCount() {
		return messages;
	}

	public long getFolderCount() {
		return folders;
	}
}
