/*******************************************************************************
 * Copyright (c) 1997, 2008 by ProSyst Software GmbH
 * http://www.prosyst.com
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    ProSyst Software GmbH - initial API and implementation
 *******************************************************************************/
package org.eclipse.equinox.internal.ip.provider.file;

import java.io.*;
import java.util.Dictionary;
import java.util.Hashtable;
import org.eclipse.equinox.internal.ip.ProvisioningInfoProvider;
import org.eclipse.equinox.internal.ip.impl.Log;
import org.eclipse.equinox.internal.ip.impl.ProvisioningAgent;
import org.eclipse.equinox.internal.ip.provider.BaseProvider;
import org.osgi.framework.BundleContext;
import org.osgi.service.provisioning.ProvisioningService;

/**
 * Loads data from inner (in jar) file or from file on hard disk. Only string
 * "TEXT" data is loaded directly into provisioning dictionary. All binaries are
 * load into inner dictionary only and are delivered only to when get method is
 * invoked.
 * 
 * @author Avgustin Marinov
 * @author Pavlin Dobrev
 * @version 1.0
 */

public class FileProvider extends BaseProvider implements ProvisioningInfoProvider {

	/** Name of configuration file. */
	public static final String PROPS_FILE = "/props.txt";

	/** This line points start of TEXT section in props.txt file */
	public static final String TEXT = "#[TEXT]";

	/** This line points start of BINARY section in props.txt file */
	public static final String BINARY = "#[BINARY]";

	/** This property is used to be determined if to be used this allowed. */
	public static final String FILE_SUPPORT = "equinox.provisioning.file.provider.allowed";

	/**
	 * This property is used to be determined if to be provider only if this
	 * provider is started for first.
	 */
	public static final String LOAD_ONCE = "equinox.provisioning.file.load.once";

	/**
	 * This dictionary keeps data that is provided by provider but is not put
	 * into provisioning data.
	 */
	private Dictionary innerDict = new Hashtable();

	/** File that is used as flag if this is first start of provider. */
	private File file;

	/**
	 * @see org.eclipse.equinox.internal.ip.impl.provider.BaseProvider#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext bc) throws Exception {
		boolean filesupport = true;
		if (bc.getProperty(FILE_SUPPORT) != null)
			if (bc.getProperty(FILE_SUPPORT).equals("false"))
				filesupport = false;
		if (!filesupport) {
			Log.debug(this + " is not an allowed provider.");
			return;
		}

		file = bc.getDataFile("_mark123");
		boolean loadonce = true;
		if (bc.getProperty(LOAD_ONCE) != null)
			if (bc.getProperty(LOAD_ONCE).equals("false"))
				loadonce = false;
		if (file.exists() && loadonce) {
			Log.debug("File provider have loaded data already!");
			return;
		}
		super.start(bc);
	}

	/**
	 * Loads data from inner (in jar) file or from file on hard disk. Data from
	 * "props" is put into provisioning data dictionary but others entries are
	 * put into "innerDict" and are available if someone request them.
	 * 
	 * @see org.eclipse.equinox.internal.ip.ProvisioningInfoProvider#init(org.osgi.service.provisioning.ProvisioningService)
	 */
	public Dictionary init(ProvisioningService prvSrv) throws Exception {
		boolean loadonce = true;
		if (ProvisioningAgent.bc.getProperty(LOAD_ONCE) != null)
			if (ProvisioningAgent.bc.getProperty(LOAD_ONCE).equals("false"))
				loadonce = false;
		if (file.exists() && loadonce) {
			Log.debug("File provider have loaded data already!");
			return null;
		}
		String externalFileLocation = ProvisioningAgent.bc.getProperty("equinox.provisioning.file.provider.specfile.location");
		BufferedReader reader = new BufferedReader(new InputStreamReader(externalFileLocation == null ? FileProvider.class.getResourceAsStream(PROPS_FILE) : new FileInputStream(externalFileLocation)));
		Dictionary dictionary = new Hashtable(10, 1.0F);
		try {
			ByteArrayOutputStream baos = null;
			byte[] buffer = null;
			int i;

			String line;
			boolean stringMode = true;
			while ((line = reader.readLine()) != null) {
				if (!(line = line.trim()).startsWith("#")) {
					if ((i = line.indexOf('=')) != -1) {
						if (stringMode) {
							dictionary.put(line.substring(0, i), line.substring(i + 1));
						} else {
							if (baos == null) {
								baos = new ByteArrayOutputStream();
								buffer = new byte[256];
							}

							String key = line.substring(0, i);
							String entryName = line.substring(i + 1);
							InputStream is;
							if (externalFileLocation == null) {
								is = FileProvider.class.getResourceAsStream(entryName);
								if (is == null && entryName.length() != 0 && entryName.charAt(0) != '/') {
									is = FileProvider.class.getResourceAsStream('/' + entryName);
								}
							} else
								is = new FileInputStream(entryName);
							for (; //
							(i = is.read(buffer, 0, buffer.length)) != -1; //
							baos.write(buffer, 0, i)) {
							}

							innerDict.put(key, baos.toByteArray());

							baos.reset();
						}
					}
				} else {
					if (line.equalsIgnoreCase(TEXT)) {
						stringMode = true;
					} else if (line.equalsIgnoreCase(BINARY)) {
						stringMode = false;
					}
				}
			}
			if (!file.exists()) {
				FileOutputStream fos = new FileOutputStream(file);
				try {
					fos.write(ZERO_BYTE_ARRAY);
				} finally {
					fos.close();
				}
			}
		} finally {
			reader.close();
		}
		return dictionary;
	}

	private static final byte[] ZERO_BYTE_ARRAY = new byte[] {0};

	/**
	 * Provides value for this key form "innnerDict".
	 * 
	 * @param key
	 *            the key.
	 * @return the value.
	 */
	public Object get(Object key) {
		return innerDict.get(key);
	}

	/**
	 * Returns name of this provider.
	 * 
	 * @return name of provider.
	 */
	public String toString() {
		return "File";
	}
}
