/*******************************************************************************
 * Copyright (c) 2008 IBM Corporation.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.cosmos.internal.dr.drs.service.handler.common;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import org.eclipse.cosmos.provisional.dr.drs.service.handler.common.AbstractOutputter;
import org.eclipse.cosmos.provisional.dr.drs.service.handler.common.IIDResolver;
import org.eclipse.cosmos.provisional.dr.drs.service.handler.common.IOutputterContext;
import org.eclipse.cosmos.provisional.dr.drs.service.handler.common.IParameters;
import org.eclipse.cosmos.provisional.dr.ps.common.IConstants;

public class QueriesOutputter extends AbstractOutputter {

	public static final String NODECLASS="nodeClass"; //$NON-NLS-1$
	protected String rootDir = ""; //$NON-NLS-1$
	protected String repoDir = ""; //$NON-NLS-1$
	
	public void initalize(IOutputterContext context, IParameters parameters) throws Exception {
		this.rootDir = context.getRealPath(IConstants.QUERYDIR);		
		this.repoDir = context.getRealPath(IConstants.QUERYREPO+File.separator+IConstants.QUERYDIR);		
		super.initalize(context, parameters);
	}
	
	public void render(PrintWriter writer, IParameters input) throws Exception {
			String nodeClass = input.getParameter(NODECLASS);
			String bundleName = context.getInitParameter( "WIDGET_BUNDLE_NAME" ); //$NON-NLS-1$

			String[] bundles = bundleName.split(","); //$NON-NLS-1$
			ResourceBundle[] RESOURCE_BUNDLES = new ResourceBundle[bundles.length];
			for (int x= 0; x< bundles.length; x++){
				RESOURCE_BUNDLES[x] = ResourceBundle.getBundle(bundles[x]);
				
			}
			
			if (nodeClass != null){
				String[] tags = nodeClass.split(","); //$NON-NLS-1$
				int count = 0;
				writer.write("{"); //$NON-NLS-1$					
				for (int y = 0; y < tags.length; y++){
					String genFilename = generateFilename(tags[y]);
					File[] files = new File[0];
					File[] repoFiles = new File[0];
					File fileExists = new File(genFilename);
					if (fileExists.exists() && fileExists.isDirectory()){
						  FileFilter fileFilter = new FileFilter() {
						        public boolean accept(File file) {
						        	return ((file.isFile()) && (file.getName().endsWith(IConstants.PROPEXT)));
						        }
						    };				
					    files = fileExists.listFiles(fileFilter);
					}
					String genRepoFilename = generateRepoFilename(tags[y]);
					fileExists = new File(genRepoFilename);
					if (fileExists.exists() && fileExists.isDirectory()){
						  FileFilter fileFilter = new FileFilter() {
						        public boolean accept(File file) {
						        	return ((file.isFile()) && (file.getName().endsWith(IConstants.PROPEXT)));
						        }
						    };				
					    repoFiles = fileExists.listFiles(fileFilter);					    					    
					}
					if ((files.length > 0) || (repoFiles.length > 0)){
						if (count > 0)
							writer.write(","); //$NON-NLS-1$
						writer.write("\""+tags[y]+"\":["); //$NON-NLS-1$ //$NON-NLS-2$
						int fileCount = 0;
						for (int x = 0; x < files.length; x++){
							if (fileCount > 0)
								writer.append(","); //$NON-NLS-1$
							generateJSON(files[x].getAbsolutePath(), writer, RESOURCE_BUNDLES, true);
							fileCount++;
						}
						for (int x = 0; x < repoFiles.length; x++){
							if (fileCount > 0)
								writer.append(","); //$NON-NLS-1$
							generateJSON(repoFiles[x].getAbsolutePath(), writer, RESOURCE_BUNDLES, false);
							fileCount++;
						}
						writer.write("]"); //$NON-NLS-1$	
						count++;
					}
				}
				writer.write("}"); //$NON-NLS-1$					
			}
			else{
				//write empty object
				writer.write("[]"); //$NON-NLS-1$
		}
	}
		
	protected String generateFilename(String tag){
		//split tag name
		String tags[] =tag.split(" "); //$NON-NLS-1$
		String newFileName = rootDir+File.separator;
		for (int x = 0; x < tags.length; x++){
			newFileName += tags[x]+File.separator;
		}
		return newFileName;
	}
	
	protected String generateRepoFilename(String tag){
		//split tag name
		String tags[] =tag.split(" "); //$NON-NLS-1$
		String newFileName = repoDir+File.separator;
		for (int x = 0; x < tags.length; x++){
			newFileName += tags[x]+File.separator;
		}
		return newFileName;
	}
	
	protected void generateQueryJSON(String filename, Writer writer) throws Exception{
		File file = new File(filename);
		if (file.isFile()){
			writer.write(", query:\""); //$NON-NLS-1$

			FileInputStream fis = null;
			ByteArrayOutputStream bos = null;
			try {
				fis = new FileInputStream(filename);
				bos = new ByteArrayOutputStream();
	
				int i;
				 
				while ((i = fis.read()) != -1)
				   bos.write(i);
				 
				fis.close();
				writer.write(escapeForMarkup(bos.toByteArray()));
				 
			} finally {
		
				if (fis != null)
					fis.close();
		
				if (bos != null)
					bos.close();
			}
			writer.write("\""); //$NON-NLS-1$
		}
		
	}
	protected void generateJSON(String filename, Writer writer, ResourceBundle RESOURCE_BUNDLE[], boolean readonly) throws Exception{
		FileInputStream fis = null;
		writer.write("{readonly:"+readonly+",meta:"); //$NON-NLS-1$ //$NON-NLS-2$
		try {
			fis = new FileInputStream(filename);

			int c;

			boolean macroStart = false;
			boolean macroStart2 = false;
			StringBuffer macroBuffer = null;
			
			while ((c = fis.read()) != -1){
				if (macroStart){
					if (((char)c) == '{'){
						macroBuffer  = new StringBuffer();
						macroStart2 = true;
					}
					else{
						writer.write('$');
						macroBuffer = null;
					}
					macroStart = false;
				}
				if (((char)c) == '$'){
					macroStart = true;
				}
				
				if (macroBuffer != null){
					if (((char)c) == '}'){
						String macroValue = "${"+macroBuffer.toString()+"}"; //$NON-NLS-1$ //$NON-NLS-2$
						for (int x = 0; x< RESOURCE_BUNDLE.length; x++){
							try {
								macroValue = RESOURCE_BUNDLE[x].getString(macroBuffer.toString());
							} catch (MissingResourceException e) {
							}
						}
						if (macroValue == null)
							macroValue = "${"+macroBuffer.toString()+"}"; //$NON-NLS-1$ //$NON-NLS-2$
						
						writer.write(macroValue);
						macroBuffer = null;							
					}
					else if (!macroStart2){
						macroBuffer.append((char)c);
					}
					else if (macroStart2){
						macroStart2 = false;
					}
				}
				else if (!macroStart){
						writer.write(c);
				}
			}
	} finally {

		if (fis != null)
			fis.close();

	}
	generateQueryJSON(filename.substring(0, filename.length()-IConstants.PROPEXT.length()) + IConstants.QUERYEXT, writer);
	writer.write("}"); //$NON-NLS-1$
		
	}
	/**
	 * Return a valid UTF8 xml encoded string from the input string buffer 
	 * provided.
	 * 
	 * @param buffer The <code>StringBuffer</code> to encode.
	 * @return The encoded string.
	 */
	public static String escapeForMarkup(byte[] buffer) {
		if (buffer == null) {
			return null;
		}
		final StringBuffer result = new StringBuffer();
		char c;
		int len = buffer.length;
		for (int i = 0; i < len; i++) {
			c = (char)buffer[i];
			switch (c) {
				case '"' :
					result.append("\\\""); //$NON-NLS-1$
					break;
				case '\r' :
					break;
				case '\n' :
					break;
				default :
						result.append(c);
			}
		}
		return result.toString();
	}

	public void setIdResolver(IIDResolver idResolver) {
		// TODO Auto-generated method stub

	}
	
	public static final void main(String[] argv) throws Exception{
		PrintWriter pw = new PrintWriter(System.out);
		QueriesOutputter out = new QueriesOutputter();
		out.rootDir = "D:\\development\\wtp30\\eclipse\\workspace\\org.eclipse.cosmos.dr.tests.views\\WebContent\\queries"; //$NON-NLS-1$
		Map input = new HashMap();
		input.put(QueriesOutputter.NODECLASS, "mdrExample"); //$NON-NLS-1$
		out.render(pw, new MapParameterImpl(input));
		pw.flush();
		pw.close();
	}


}
