/*******************************************************************************
 * 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.ps.common;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;

public class Configuration implements Map{
	protected static final String EQUAL = "=";
	protected static final String COMMENT = "#";
	protected static final String TITLE = "@title";
	protected static final String DESCRIPTION = "@description";
	protected static final String RESOURCE = "@resource";
	protected static final String NAME = "@name";
	protected Map<String,ConfigurationItem> map = new Hashtable<String, ConfigurationItem>();
	protected String title;
	
	public String getTitle() {
		return title;
	}
	public boolean load(InputStream reader) throws Exception{
		return load(new InputStreamReader(reader));		
	}

	public boolean load(String filename) throws Exception{
		File file = new File(filename);
		//make sure that the file exists
		if (!file.exists())
			return false;
		return load(new FileReader(filename));
	}
	public boolean load(Reader reader) throws Exception{	
		 BufferedReader in = new BufferedReader(reader);	
		 String readLine = null;
		 String description = null;
		 ResourceBundle[] RESOURCE_BUNDLES = null;
		 String name = null;
		 while ((readLine = in.readLine()) != null){
			 if (readLine.trim().startsWith(COMMENT)){
				 int idx = readLine.indexOf(RESOURCE);
				 if (idx > 0){
					 	String bundleName = readLine.substring(idx+RESOURCE.length(), readLine.length());
						String[] bundles = bundleName.split(",");
						RESOURCE_BUNDLES = new ResourceBundle[bundles.length];
						for (int x= 0; x< bundles.length; x++){
							try {
								RESOURCE_BUNDLES[x] = ResourceBundle.getBundle(bundles[x].trim());
							} catch (RuntimeException e) {
							}
							
						}
				 }
				 idx = readLine.indexOf(DESCRIPTION);
				 if (idx > 0){
					 description = resolveMacro(readLine.substring(idx+DESCRIPTION.length(), readLine.length()), RESOURCE_BUNDLES);
				 }
				 idx = readLine.indexOf(TITLE);
				 if (idx > 0){
					 title = resolveMacro(readLine.substring(idx+TITLE.length(), readLine.length()), RESOURCE_BUNDLES);
				 }
				 idx = readLine.indexOf(NAME);
				 if (idx > 0){
					 name = resolveMacro(readLine.substring(idx+NAME.length(), readLine.length()), RESOURCE_BUNDLES);
				 }
				 
			 }
			 else{
				 int idx = readLine.indexOf(EQUAL);
				 if (idx > 0){
					 String attribute = readLine.substring(0, idx);
					 String value = readLine.substring(idx+1, readLine.length());
					 map.put(attribute, new ConfigurationItem(description, name, attribute, value));					 
				 }
			 }
		 }
		 in.close();
		 return true;
	}
	
	protected String resolveMacro(String line, ResourceBundle RESOURCE_BUNDLE[]){
		boolean macroStart = false;
		boolean macroStart2 = false;
		StringBuffer macroBuffer = null;
		StringBuffer writer = new StringBuffer();
		char[] chars = line.toCharArray();
		char c;
		for (int z = 0; z < chars.length; z++){
			c = chars[z];
			if (macroStart){
				if ((c) == '{'){
					macroBuffer  = new StringBuffer();
					macroStart2 = true;
				}
				else{
					writer.append('$');
					macroBuffer = null;
				}
				macroStart = false;
			}
			if (((char)c) == '$'){
				macroStart = true;
			}
			
			if (macroBuffer != null){
				if (((char)c) == '}'){
					String macroValue = "";
					if (RESOURCE_BUNDLE != null){
						for (int x = 0; x< RESOURCE_BUNDLE.length; x++){
							try {
								if (RESOURCE_BUNDLE[x] != null)
									macroValue = RESOURCE_BUNDLE[x].getString(macroBuffer.toString());
							} catch (MissingResourceException e) {
							}
						}
					}
					if (macroValue == null)
						macroValue = "";
					
					writer.append(macroValue);
					macroBuffer = null;							
				}
				else if (!macroStart2){
					macroBuffer.append(c);
				}
				else if (macroStart2){
					macroStart2 = false;
				}
			}
			else if (!macroStart){
					writer.append(c);
			}
		}
		return writer.toString();
		
	}
	public void save(String filename) throws Exception{
		BufferedWriter out = new BufferedWriter(new FileWriter(filename));
		Iterator<String> iter = map.keySet().iterator();
		out.write(COMMENT+ " " + TITLE + " " +getTitle());
		out.newLine();
		while (iter.hasNext()){
			String key = iter.next();
			ConfigurationItem ci = map.get(key);
			out.write(COMMENT+ " " + NAME + " " +ci.getDisplayName());
			out.newLine();
			out.write(COMMENT+ " " + DESCRIPTION + " " +ci.getDescription());
			out.newLine();
			out.write(ci.getName()+EQUAL+ci.getValue());
			out.newLine();
		}
		 out.close();
	}
	public void clear() {
		map.clear();
	}
	public boolean containsKey(Object key) {
		return map.containsKey(key);
	}
	public boolean containsValue(Object value) {
		return map.containsValue(value);
	}
	public Set<Entry<String, ConfigurationItem>> entrySet() {
		return map.entrySet();
	}
	public boolean equals(Object o) {
		return map.equals(o);
	}
	public ConfigurationItem get(Object key) {
		return map.get(key);
	}
	public String getValue(Object key) {
		ConfigurationItem ci = get(key);
		if (ci != null)
			return ci.getValue();
		return null;
	}
	public int hashCode() {
		return map.hashCode();
	}
	public boolean isEmpty() {
		return map.isEmpty();
	}
	public Set<String> keySet() {
		return map.keySet();
	}
	public ConfigurationItem put(String key, ConfigurationItem value) {
		return map.put(key, value);
	}
	public ConfigurationItem remove(Object key) {
		return (ConfigurationItem)map.remove(key);
	}
	public Object put(Object key, Object value) {
		return map.put((String)key, (ConfigurationItem)value);
	}
	public void putAll(Map t) {
		map.putAll(t);		
	}
	public int size() {
		return map.size();
	}
	public Collection<ConfigurationItem> values() {
		return map.values();
	}
	

}
