/*
 * This file is part of the DistSim distributed simulation framework (client)
 * Copyright (C) 2007 Ulf Hermann
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package brn.distsim.client.data;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class GroupConfigurationFiles extends
		DbBackedProperties<GroupConfigurationFiles.File> {

	protected PreparedStatement writeFile;

	public final static String TABLE_NAME = "group_in_files";

	/**
	 * a Configuration file has a name - the path on the simulating host - and
	 * either a localpath - the path where the file should be fetched from when
	 * loading into the DB - or an id if it already is in the DB.
	 *
	 * @author alve
	 *
	 */
	public class File extends DbBackedProperties.Property {

		protected int fileId;
    private boolean isContent = false;

		public File(String remotePath, String localPath) {
			super(remotePath, localPath);
			fileId = 0;
		}

    public File(String remotePath, String content, boolean isContent) {
      super(remotePath, content);
      fileId = 0;
      this.isContent = true;
    }

    public File(ResultSet data) throws SQLException {
			super(data.getString("remotePath"), null);
			fileId = data.getInt("fileId");
		}

		protected File(String remotePath, String localPath, int fileId) {
			super(remotePath, localPath);
			this.fileId = fileId;
		}

		public int getFileId() {
			return fileId;
		}

		public void performDbInsert(int groupId) throws SQLException {
			id = groupId;
			String idString;
			if (value != null) {
				idString = "LAST_INSERT_ID()";
        if  (!isContent)
          writeFileToDB(value);
        else
          writeFileToDB(new ByteArrayInputStream(value.getBytes()));
			} else {
				idString = "'" + fileId + "'";
      }
			String sql = "INSERT INTO " + TABLE_NAME + " VALUES ('";
			sql += id;
			sql += "', '" + name;
			sql += "', " + idString + ");";
			statement.execute(sql);
		}

		public void performDbDelete() throws SQLException {
			statement.execute("DELETE FROM " + TABLE_NAME + " WHERE groupId='"
					+ id + "' AND remotePath='" + name + "';");
		}

		public void performDbUpdate() throws SQLException {
			writeFileToDB(value);
			String sql = "UPDATE " + TABLE_NAME
					+ " SET fileId=LAST_INSERT_ID()  WHERE groupName='" + id
					+ "' AND  remotePath='" + name + "';";
			statement.execute(sql);
		}
	}

	public GroupConfigurationFiles(Connection definitions, int groupId) {
		super(definitions, groupId);
		try {
			writeFile = definitions
					.prepareStatement("INSERT IGNORE INTO in_files set content = ?;");
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public GroupConfigurationFiles(GroupConfigurationFiles other) {
		super(other);
		try {
			writeFile = definitions
					.prepareStatement("INSERT IGNORE INTO in_files set content = ?;");
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public GroupConfigurationFiles(Connection db, int id, ResultSet set)
			throws SQLException {
		super(db, id, set);
		writeFile = definitions
				.prepareStatement("INSERT IGNORE INTO in_files set content = ?;");
	}

	/**
	 * TODO throw FileNotFoundException to indicate errors
	 * @param file
	 * @throws SQLException
	 */
  private void writeFileToDB(String file) throws SQLException {
    try {
      FileInputStream stream = new FileInputStream(file);
      writeFileToDB(stream);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
  }

  private void writeFileToDB(InputStream stream) throws SQLException {
    try {
      writeFile.setBinaryStream(1, stream, stream.available());
      writeFile.executeUpdate();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

	public int getFileId(String remotePath) {
		return entries.get(remotePath).getFileId();
	}

	@Override
	public File getEmptyDependent() {
		return new File(null, null);
	}

	@Override
	public File getDependent(ResultSet data) throws SQLException {
		return new File(data);
	}

	@Override
	public File getDependent(File other) {
		return new File(other.name, other.value, other.fileId);
	}

	@Override
	public void loadFromDb() throws SQLException {
		ResultSet files = statement.executeQuery("SELECT * FROM " + TABLE_NAME
				+ " WHERE groupId=" + id + ";");
		loadFromDb(files);
	}

	/**
	 * get the names of all configuration files belonging to the specified study
	 *
	 * @param db
	 * @param studyId
	 * @return the names of all configuration files belonging to the specified study
	 * @throws SQLException
	 */
	public static List<String> getNames(Connection db, int studyId)
			throws SQLException {
		ResultSet names = db
				.createStatement()
				.executeQuery(
						"SELECT DISTINCT remotePath FROM "
								+ TABLE_NAME
								+ " WHERE groupId in (SELECT id FROM groups WHERE studyId="
								+ studyId + ");");
		return namesToList(names);
	}

}
