/**
 * 
 */
package cz.neubauer.tomas.hazardanalysis.model.components;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import cz.neubauer.tomas.hazardanalysis.model.dangers.DangerGroup;
import cz.neubauer.tomas.hazardanalysis.model.dangers.DangerType;
import cz.neubauer.tomas.hazardanalysis.model.dangers.DangerVariant;

/**
 * Třída, která představuje katalog komponent. Obsahuje kolekci komponent včetně
 * jim přiřazené hierarchie nebezpečí.
 * 
 * @author Tomáš Neubauer
 */
public class ComponentCatalog {

	/**
	 * Kolekce komponent.
	 */
	private ArrayList<Component> components;

	/**
	 * Vytvoří katalog s prázdnou kolekcí komponent.
	 */
	public ComponentCatalog() {
		components = new ArrayList<Component>(10);
	}

	/**
	 * Vloží do katalogu danou komponentu.
	 * 
	 * @param component
	 *            Vkládaná komponenta.
	 */
	public void addComponent(Component component) {
		components.add(component);
	}

	/**
	 * Vloží do katalogu novou komponentu na pozici s daným indexem.
	 * 
	 * @param index
	 *            Index pozice komponenty.
	 * @param component
	 *            Vkládaná komponenta.
	 */
	public void setComponent(int index, Component component) {
		components.set(index, component);
	}

	/**
	 * Vrátí komponentu, která se nachází v katalogu na pozici s daným indexem
	 * 
	 * @param index
	 *            Index pozice komponenty v katalogu.
	 * @return Komponenta na dané pozici.
	 */
	public Component getComponent(int index) {
		return components.get(index);
	}

	/**
	 * Vyhledá a vrátí komponentu podle jejího názvu.
	 * 
	 * @param name
	 *            Název hledané komponenty.
	 * @return Pokud se komponenta s danám názvem v katalogu nachází, je
	 *         vráceba, jinak metoda vrací <code>null</code>.
	 */
	public Component getComponentByName(String name) {
		int count = getCount();

		Component c;
		for (int i = 0; i < count; i++) {
			c = getComponent(i);
			if (c.getName().compareToIgnoreCase(name) == 0) {
				return c;
			}
		}
		return null;
	}

	/**
	 * Vrátí aktuální počet komponent.
	 * 
	 * @return Počet komponent v katalogu.
	 */
	public int getCount() {
		return components.size();
	}

	/**
	 * Načte katalog z databáze prostřednictvím daného připojení.
	 * 
	 * @param connection
	 *            Připojení k databázi.
	 */
	public void loadFromDB(Connection connection) {
		if (connection != null) {
			try {
				Statement stmt = connection.createStatement();
				Statement stmt2 = connection.createStatement();
				ResultSet rs = stmt.executeQuery("SELECT * FROM component;");

				components.clear();
				String componentName, componentLocation;
				int componentId;
				ResultSet rs2;
				while (rs.next()) {
					componentId = rs.getInt("id");
					componentName = rs.getString("name");
					componentLocation = rs.getString("location");

					rs2 = stmt2
							.executeQuery("select"
									+ " dg.id as dg_id,"
									+ " dg.name as dg_name,"
									+ " dt.id as dt_id,"
									+ " dt.code as dt_code,"
									+ " dt.description as dt_description,"
									+ " dt.column_cast2_a1_1995 as dt_column_cast2_a1_1995,"
									+ " dt.column_cast1_r1991 as dt_column_cast1_R1991,"
									+ " dt.column_cast2_r1991 as dt_column_cast2_R1991,"
									+ " dt.column_csn_en_iso_12100_1_2003 as dt_column_csn_en_iso_12100_1_2003,"
									+ " dt.column_csn_en_iso_12100_2_2003 as dt_column_csn_en_iso_12100_2_2003,"
									+ " dt.column_normy_typu_b as dt_column_normy_typu_b,"
									+ " dt.column_clanky_csn_en_12415_2001 as dt_column_clanky_csn_en_12415_2001,"
									+ " dt.situation_description as dt_situation_description,"
									+ " dv.id as dv_id,"
									+ " dv.danger_type_id as dv_danger_type_id,"
									+ " dv.description as dv_description"
									+ " from ((component_danger_variant cdv join danger_variant dv on ( cdv.danger_variant_id = dv.id)) join danger_type dt on (dv.danger_type_id = dt.id)) join danger_group dg on (dt.danger_group_id = dg.id) where cdv.component_id = '"
									+ componentId + "';");

					Component newComponent = new Component(componentId,
							componentName, componentLocation);
					int oldDGID = 0, currentDGID;
					int oldDTID = 0, currentDTID;
					int oldDVID = 0, currentDVID;
					DangerGroup dg = null;
					DangerType dt = null;
					DangerVariant dv = null;
					while (rs2.next()) {
						currentDGID = rs2.getInt("dg_id");
						if (currentDGID != oldDGID) {
							dg = new DangerGroup(currentDGID, rs2
									.getString("dg_name"));
							newComponent.addDangerGroup(dg);
							oldDGID = currentDGID;
						}

						currentDTID = rs2.getInt("dt_id");
						if (currentDTID != oldDTID) {
							dt = new DangerType(
									dg,
									currentDTID,
									rs2.getString("dt_code"),
									rs2.getString("dt_description"),
									rs2.getString("dt_column_cast1_r1991"),
									rs2.getString("dt_column_cast2_r1991"),
									rs2
											.getString("dt_column_csn_en_iso_12100_1_2003"),
									rs2
											.getString("dt_column_csn_en_iso_12100_2_2003"),
									rs2
											.getString("dt_column_csn_en_iso_12100_2_2003"),
									rs2.getString("dt_column_normy_typu_b"),
									rs2
											.getString("dt_column_clanky_csn_en_12415_2001"),
									rs2.getString("dt_situation_description"));
							dg.addDangerType(dt);
							oldDTID = currentDTID;
						}

						currentDVID = rs2.getInt("dv_id");
						if (currentDVID != oldDVID) {
							dv = new DangerVariant(dt, rs2.getInt("dv_id"), rs2
									.getString("dv_description"));
							dt.addDangerVariant(dv);
							oldDVID = currentDVID;
						}
					}
					addComponent(newComponent);
				}
				stmt2.close();
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * Vyprázdní katalog.
	 */
	public void clear() {
		components.clear();
	}

	/**
	 * Vrátí kolekci komponent.
	 * 
	 * @return Kolekce komonent.
	 */
	public ArrayList<Component> getComponents() {
		return components;
	}

	/**
	 * Prohledá katalog a vrátí kolekci všech variant nebezpečí, které jsou
	 * označeny jako závažné (kritické).
	 * 
	 * @return Kolekci závažných variant nebezpečí.
	 */
	public ArrayList<DangerVariant> getCriticalVariants() {
		ArrayList<DangerVariant> criticalVariants = new ArrayList<DangerVariant>(
				10);

		int componentCount = getCount();
		Component c;
		for (int i = 0; i < componentCount; i++) {
			c = getComponent(i);

			int groupCount = c.getDangerGroupCount();
			DangerGroup dg;
			for (int j = 0; j < groupCount; j++) {
				dg = c.getDangerGroup(j);

				int typeCount = dg.getDangerTypeCount();
				DangerType dt;
				for (int k = 0; k < typeCount; k++) {
					dt = dg.getDangerType(k);

					int variantCount = dt.getDangerVariantCount();
					DangerVariant dv;
					for (int l = 0; l < variantCount; l++) {
						dv = dt.getDangerVariant(l);

						if (dv.isCritical()) {
							criticalVariants.add(dv);
						}
					}
				}
			}
		}

		return criticalVariants;
	}
}
