/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.sed;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.List;

public class Sed {

	public static int execute(SedCommandBundle b, Reader command,
			Reader reader, Writer writer, SedPatternEngine engine,
			boolean display) throws IOException {
		List<SedCommandLine> cmds;

		cmds = SedParser.parse(b, command);
		return SedEngine.execute(reader, writer, engine, display,
				cmds.toArray(new SedCommandLine[0]));
	}

	public static int execute(SedCommandBundle b, String command,
			Reader reader, Writer writer, SedPatternEngine engine,
			boolean display) throws IOException {
		return execute(b, new StringReader(command), reader, writer,
				engine, display);
	}

	public static int execute(Reader command,
			Reader reader, Writer writer, SedPatternEngine engine,
			boolean display) throws IOException {
		return execute(SedCommandBundle.newInstance(), command,
				reader, writer, engine, display);
	}

	public static int execute(String command,
			Reader reader, Writer writer, SedPatternEngine engine,
			boolean display) throws IOException {
		return execute(SedCommandBundle.newInstance(),
				new StringReader(command), reader, writer,
				engine, display);
	}

	public static void execute(SedCommandBundle bl, String command,
			File inputFile, File outputFile,
			Charset inputEncoding, Charset outputEncoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		Reader rd = null;
		Writer wr = null;

		try {
			if(inputEncoding != null) {
				rd = new InputStreamReader(
						new FileInputStream(inputFile),
						inputEncoding);
			} else {
				rd = new InputStreamReader(
						new FileInputStream(inputFile));
			}

			if(outputEncoding != null) {
				wr = new OutputStreamWriter(
						new FileOutputStream(outputFile),
						outputEncoding);
			} else {
				wr = new OutputStreamWriter(
						new FileOutputStream(outputFile));
			}
			execute(bl, command, rd, wr, engine, display);
		} finally {
			if(rd != null)  rd.close();
			if(wr != null) {
				wr.flush();
				wr.close();
			}
		}
	}

	public static void executeAndOverwrite(SedCommandBundle bl,
			String command, File file,
			Charset inputEncoding, Charset outputEncoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		File tf = File.createTempFile("sedaf", ".tmp");
		BufferedOutputStream ous = null;
		BufferedInputStream ins = null;
		byte[] b = new byte[4096];
		int l;

		try {
			execute(bl, command, file, tf,
					inputEncoding, outputEncoding, engine, display);
			ins = new BufferedInputStream(new FileInputStream(tf));
			ous = new BufferedOutputStream(
					new FileOutputStream(file));
			while((l = ins.read(b)) >= 0)  ous.write(b, 0, l);
		} finally {
			if(ins != null)  ins.close();
			if(ous != null) {
				ous.flush();
				ous.close();
			}
			tf.delete();
		}
	}

	public static String execute(SedCommandBundle b,
			String command, String input,
			Charset inputEncoding, Charset outputEncoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		StringReader rd = new StringReader(input);
		StringWriter wr = new StringWriter();

		execute(b, command, rd, wr, engine, display);
		return wr.toString();
	}

	public static void executeOnlyInput(SedCommandBundle bl,
			String command, File file,
			Charset encoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		Reader rd = null;
		Writer wr = new NullWriter();

		try {
			if(encoding != null) {
				rd = new InputStreamReader(
						new FileInputStream(file),
						encoding);
			} else {
				rd = new InputStreamReader(
						new FileInputStream(file));
			}
			execute(bl, command, rd, wr, engine, display);
		} finally {
			if(rd != null)  rd.close();
		}
	}

	public static void execute(SedCommandBundle bl, String command,
			File inputFile, File outputFile,
			String inputEncoding, String outputEncoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		execute(bl, command, inputFile, outputFile,
				Charset.forName(inputEncoding),
				Charset.forName(outputEncoding),
				engine, display);
	}

	public static void executeAndOverwrite(SedCommandBundle bl,
			String command, File file,
			String inputEncoding, String outputEncoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		executeAndOverwrite(bl, command, file,
				Charset.forName(inputEncoding),
				Charset.forName(outputEncoding),
				engine, display);
	}

	public static String execute(SedCommandBundle b,
			String command, String input,
			String inputEncoding, String outputEncoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		return execute(b, command, input,
				Charset.forName(inputEncoding),
				Charset.forName(outputEncoding),
				engine, display);
	}

	public static void executeOnlyInput(SedCommandBundle bl,
			String command, File file, String encoding,
			SedPatternEngine engine,
			boolean display) throws IOException {
		executeOnlyInput(bl, command, file, Charset.forName(encoding),
				engine, display);
	}

}
