package siprp.higiene.relatorio.print;

import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Vector;

import siprp.planoactuacao.db.DBConstants;

import com.evolute.utils.Singleton;
import com.evolute.utils.arrays.Virtual2DArray;
import com.evolute.utils.data.Mappable;
import com.evolute.utils.data.MappableObject;
import com.evolute.utils.db.DBManager;
import com.evolute.utils.db.Executer;
import com.evolute.utils.sql.BlobUpdate;
import com.evolute.utils.sql.Expression;
import com.evolute.utils.sql.Field;
import com.evolute.utils.sql.Select;
import com.evolute.utils.sql.Select2;


public class RelatorioPrintDataProvider
{
	private static final Object LOCK = new Object();
	protected static final Object CONTROLLED = "Controlado";
	protected static final Object INDETERMINATE = "Indeterminado";
	private static RelatorioPrintDataProvider instance = null;
	
	protected final Executer EXECUTER;

	public RelatorioPrintDataProvider()
		throws Exception
	{
		if( Singleton.getInstance( DBConstants.LOCAL_DBMANAGER ) == null )
		{
			RelatorioDBInit.initDB();
		}
		DBManager LOCAL_DBMANAGER = ( DBManager ) Singleton.getInstance( DBConstants.LOCAL_DBMANAGER );
		EXECUTER = LOCAL_DBMANAGER.getSharedExecuter( this );
	}
	
	public static RelatorioPrintDataProvider getProvider()
		throws Exception
	{
		synchronized( LOCK )
		{
			if( instance == null )
			{
				instance = new RelatorioPrintDataProvider();
			}
		}
		return instance;
	}
	
	public boolean empresaUsaPlanoAlargadoPorPlanoId( Integer planoId )
		throws Exception
	{
		try
		{
			Select select = 
				new Select2( 
					new String[]{ "hs_relatorio", "marcacoes_estabelecimento", "estabelecimentos", "empresas" },
					new Integer[]{ Select2.JOIN_INNER, Select2.JOIN_INNER, Select2.JOIN_INNER },
					new Expression[]{
						new Field( "hs_relatorio.marcacao_id" ).isEqual( new Field( "marcacoes_estabelecimento.id" ) ),
						new Field( "marcacoes_estabelecimento.estabelecimento_id" ).isEqual( new Field( "estabelecimentos.id" ) ),
						new Field( "estabelecimentos.empresa_id" ).isEqual( new Field( "empresas.id" ) )
					},
					new String[]{ "imprimir_tabela_alargada" },
					new Field( "hs_relatorio.id" ).isEqual( planoId ),
					null,
					null,
					null,
					null );
			Virtual2DArray array = EXECUTER.executeQuery( select );
			
			return ( ( Boolean ) array.get( 0, 0 ) ).booleanValue();
		}
		catch( Exception ex )
		{
			return true;
		}
	}
	
	
	public RelatorioToPrint getRelatorioToPrint( Integer id )
		throws Exception
	{
		Virtual2DArray array; 
		
		Select select =
			new Select2( 
				new String[]{ "hs_relatorio", "marcacoes_estabelecimento", "estabelecimentos", "empresas" },
				new Integer[]{ Select2.JOIN_INNER, Select2.JOIN_INNER, Select2.JOIN_INNER },
				new Expression[]{
					new Field( "hs_relatorio.marcacao_id" ).isEqual( new Field( "marcacoes_estabelecimento.id" ) ),
					new Field( "marcacoes_estabelecimento.estabelecimento_id" ).isEqual( new Field( "estabelecimentos.id" ) ),
					new Field( "estabelecimentos.empresa_id" ).isEqual( new Field( "empresas.id" ) )
				},
				new String[]{ "empresas.id", "empresas.designacao_social", "empresas.actividade", 
						"estabelecimentos.id", "estabelecimentos.nome", 
						"hs_relatorio.data", "marcacoes_estabelecimento.data",
						"hs_relatorio.acompanhante1", "hs_relatorio.funcao_acompanhante1",
						"hs_relatorio.funcionarios", "estabelecimentos.morada",
						"hs_relatorio.avaliacao_inicial"},
				new Field( "hs_relatorio.id" ).isEqual( id ),
				null,
				null,
				null,
				null );
		array = EXECUTER.executeQuery( select );
		Integer empresaId = ( Integer ) array.get( 0, 0 );
		String nomeEmpresa = ( String ) array.get( 0, 1 );
		String actividadeEmpresa = ( String ) array.get( 0, 2 );
		Integer estabelecimentoId = ( Integer ) array.get( 0, 3 );
		String nomeEstabelecimento = ( String ) array.get( 0, 4 );
		Integer logoId = getLogotipoIdForEmpresaId( empresaId );
		Date dataRelatorio = ( Date ) array.get( 0, 5 );
		Date dataVisita = ( Date ) array.get( 0, 6 );
		Date dataProximaVisita = getDataProximaVisita( estabelecimentoId, dataVisita );
		String nomeAcompanhante = ( String ) array.get( 0, 7 );
		String funcaoAcompanhante = ( String ) array.get( 0, 8 );
		String textoFuncionarios = ( String ) array.get( 0, 9 );
		String morada = ( String ) array.get( 0, 10 );
		String tipoAvaliacao = ( array.get( 0, 11 ) != null && ( ( Boolean ) array.get( 0, 11 ) ).booleanValue() ) ? "INICIAL" : "PERI\u00d3DICA";
		EmpresaToPrint empresa = new EmpresaToPrint( nomeEmpresa,
				"http://www.evolute.pt:13080/SIPRPImages/image?id=" + logoId,
				nomeEstabelecimento, actividadeEmpresa,
				nomeAcompanhante, funcaoAcompanhante, morada );
		RelatorioToPrint plano = 
			new RelatorioToPrint( 
				empresa, 
				dataRelatorio != null ? new DataToPrint( "data-relatorio", dataRelatorio ) : null, 
				dataVisita != null ? new DataToPrint( "data-hs", dataVisita ) : null,
				tipoAvaliacao,
				dataProximaVisita != null ? new DataToPrint( "data-proxima-hs", dataProximaVisita ) : null,
				textoFuncionarios,
				getTecnicoHS( id ),
				getLegislacaoAplicavel( id ),
				getNormalizacaoAplicavel( id ),
				getEquipamento( id ),
				getAreasToPrint( id ) );
		return plano; 
	}
	
	public Date getDataProximaVisita( Integer estabelecimentoId, Date dataVisita )
		throws Exception
	{
		Select select =
			new Select2(
				new String[]{ "marcacoes_estabelecimento" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "MIN( marcacoes_estabelecimento.data )" },
				new Field( "marcacoes_estabelecimento.estabelecimento_id" ).isEqual( estabelecimentoId ).and( 
					new Field( "marcacoes_estabelecimento.data" ).isGreater( dataVisita ) ).and( 
					new Field( "marcacoes_estabelecimento.estado" ).isEqual( 0 ) ),
				null,
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		if( array.columnLength() == 0 )
		{
			return null;
		}
		else
		{
			return ( Date ) array.get( 0, 0 );
		}
	}
	
	public Integer getLogotipoIdForEmpresaId( Integer empresaId )
		throws Exception
	{
		Select select = 
			new Select2(
				new String[]{ "empresas" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "empresa_logo_id" },
				new Field( "id" ).isEqual( empresaId ),
				null,
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		return array.columnLength() > 0 ? ( Integer ) array.get( 0, 0 ) : null;
	}
	
	public TecnicoHSToPrint getTecnicoHS( Integer relatorioId )
		throws Exception
	{
		Select select =
			new Select2(
				new String[]{ "hs_relatorio", "marcacoes_estabelecimento", "marcacoes_tecnicos_hst" },
				new Integer[]{ Select2.JOIN_INNER, Select2.JOIN_INNER },
				new Expression[]{
					new Field( "hs_relatorio.marcacao_id" ).isEqual( new Field( "marcacoes_estabelecimento.id" ) ),
					new Field( "marcacoes_estabelecimento.tecnico_hst" ).isEqual( new Field( "marcacoes_tecnicos_hst.id" ) ),
				},
				new String[]{ 
					"marcacoes_tecnicos_hst.id", 
					"marcacoes_tecnicos_hst.nome",
					"marcacoes_tecnicos_hst.cap",
					"marcacoes_tecnicos_hst.formacao",
					"marcacoes_tecnicos_hst.assinatura",},
				new Field( "hs_relatorio.id" ).isEqual( relatorioId ),
				null,
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		if( array.columnLength() == 0 )
		{
			return null;
		}
		else
		{
			Integer id = ( Integer ) array.get( 0, 0 );
			String nome = ( String ) array.get( 0, 1 );
			String cap = ( String ) array.get( 0, 2 );
			String formacao = ( String ) array.get( 0, 3 );
			Integer assinatura = ( Integer ) array.get( 0, 4 );
			return new TecnicoHSToPrint( id, nome, cap, formacao, "http://www.evolute.pt:13080/SIPRPImages/image?id=" + assinatura );
		}
	}
	
	public LegislacaoAplicavelToPrint getLegislacaoAplicavel( Integer relatorioId )
		throws Exception
	{
		Select select =
			new Select2( 
				new String[]{ "hs_relatorio_legislacao" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "hs_relatorio_legislacao.categoria", "hs_relatorio_legislacao.descricao" },
				new Field( "hs_relatorio_legislacao.hs_relatorio_id" ).isEqual( relatorioId ),
				new String[]{ "hs_relatorio_legislacao.categoria DESC" },
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		Vector<String> diplomasGerais = new Vector<String>();
		Vector<String> nomes = new Vector<String>();
		Vector<Vector<String>> diplomas = new Vector<Vector<String>>();
		String last = null;
		for( int n = 0; n < array.columnLength(); n++ )
		{
			String categoria = ( String ) array.get( n, 0 );
			String descricao = ( String ) array.get( n, 1 );
			if( categoria == null || categoria.trim().length() == 0 )
			{
				diplomasGerais.add( descricao );
			}
			else
			{
				if( !categoria.equals( last ) )
				{
					nomes.add( categoria );
					diplomas.add( new Vector<String>() );
				}
				last = categoria;
				diplomas.lastElement().add( descricao );
			}
		}
		LegislacaoAplicavelToPrint legislacao = 
			new LegislacaoAplicavelToPrint( diplomasGerais, nomes.toArray( new String[ nomes.size() ] ),
					diplomas.toArray( new Vector[ diplomas.size() ] ));
		return legislacao;
	}
	
	public NormalizacaoToPrint getNormalizacaoAplicavel( Integer relatorioId )
		throws Exception
	{
		Select select = 
			new Select2( 
				new String[]{ "hs_relatorio_normalizacao" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "hs_relatorio_normalizacao.portuguesa", "hs_relatorio_normalizacao.descricao" },
				new Field( "hs_relatorio_normalizacao.hs_relatorio_id" ).isEqual( relatorioId ),
				new String[]{ "hs_relatorio_normalizacao.portuguesa", "hs_relatorio_normalizacao.descricao" },
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		Vector<String> portuguesas = new Vector<String>();
		Vector<String> internacionais = new Vector<String>();
		for( int n = 0; n < array.columnLength(); n++ )
		{
			Boolean portuguesa = ( Boolean ) array.get( n, 0 );
			String descricao = ( String ) array.get( n, 1 );
			if( portuguesa )
			{
				portuguesas.add( descricao );
			}
			else
			{
				internacionais.add( descricao );
			}
		}
		return new NormalizacaoToPrint( portuguesas, internacionais );
	}
	
	public EquipamentosToPrint getEquipamento( Integer relatorioId )
		throws Exception
	{
		Select select = 
			new Select2(
				new String[]{ "hs_relatorio_equipamento" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "hs_relatorio_equipamento.tipo", "hs_relatorio_equipamento.marca", 
						"hs_relatorio_equipamento.modelo" },
				new Field( "hs_relatorio_equipamento.hs_relatorio_id" ).isEqual( relatorioId ),
				null,
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		EquipamentoToPrint equipamentos[] = new EquipamentoToPrint[ array.columnLength() ]; 
		for( int n = 0; n < array.columnLength(); n++ )
		{
			String tipo = ( String ) array.get( n, 0 );
			String marca = ( String ) array.get( n, 1 );
			String modelo = ( String ) array.get( n, 2 );
			equipamentos[ n ] = new EquipamentoToPrint( tipo, marca, modelo );
		}
		return new EquipamentosToPrint( equipamentos );
	}
	
	public Vector<AreaToPrint> getAreasToPrint( Integer relatorioId )
		throws Exception
	{
		Virtual2DArray array;
		Vector<AreaToPrint> areas = new Vector<AreaToPrint>();
		
		Select select = 
			new Select2( 
				new String[]{ "hs_relatorio_area" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "id", "description" },
				new Field( "relatorio_id" ).isEqual( relatorioId ).and(
					new Field( "deleted_date" ).isEqual( null ) ),
				new String[]{ "id" },
				null,
				null,
				null );
		array = EXECUTER.executeQuery( select );

		for( int n = 0; n < array.columnLength(); n++ )
		{
			Integer areaId = ( Integer ) array.get( n, 0 );
			String areaDescricao = ( String ) array.get( n, 1 );
			Vector<PostoToPrint> postos = getPostosToPrintByAreaId( areaId );
			if( postos.size() > 0 )
			{
				areas.add( new AreaToPrint( areaDescricao, postos ) );
			}
		}
		return areas;
	}
	
	public Vector<PostoToPrint> getPostosToPrintByAreaId( Integer areaId )
		throws Exception
	{
		Vector<PostoToPrint> postos = new Vector<PostoToPrint>();
		Virtual2DArray array;
		Select select = 
			new Select2( 
				new String[]{ "hs_relatorio_posto" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "hs_relatorio_posto.id", "hs_relatorio_posto.description" },
				new Field( "hs_relatorio_posto.area_id" ).isEqual( areaId ),
				new String[]{ "hs_relatorio_posto.id" },
				null,
				null,
				null );
		array = EXECUTER.executeQuery( select );
		for( int n = 0; n < array.columnLength(); n++ )
		{
			Integer id = ( Integer ) array.get( n, 0 );
			String descricao = ( String ) array.get( n, 1 );
			postos.add( new PostoToPrint( descricao, getRiscosToPrintByPostoId( id ) ) );
		}
		return postos;
	}
	
	public Vector<RiscoToPrint> getRiscosToPrintByPostoId( Integer postoId )
		throws Exception
	{
		Virtual2DArray array;
		Vector<RiscoToPrint> riscos = new Vector<RiscoToPrint>();
		Select select = 
			new Select2( 
				new String[]{ "hs_relatorio_risco", "hs_relatorio_posto_risco", "hs_relatorio_risco_valor_qualitativo" },
				new Integer[]{ Select2.JOIN_INNER, Select2.JOIN_LEFT_OUTER },
				new Expression[]{
					new Field( "hs_relatorio_risco.id" ).isEqual( new Field( "hs_relatorio_posto_risco.risco_id" ) ),
					new Field( "hs_relatorio_posto_risco.valor_qualitativo_id" ).isEqual( new Field( "hs_relatorio_risco_valor_qualitativo.id" ) )
				},
				new String[]{ "hs_relatorio_risco.id", 
						"hs_relatorio_risco.description", 
						"hs_relatorio_posto_risco.probabilidade",
						"hs_relatorio_posto_risco.severidade", 
						"hs_relatorio_risco_valor_qualitativo.description" },
				new Field( "hs_relatorio_posto_risco.posto_id" ).isEqual( postoId ).and( 
					new Field( "hs_relatorio_risco.deleted_date" ).isEqual( null ).and(
							new Field("hs_relatorio_posto_risco.probabilidade").isDifferent(null).or(
							new Field("hs_relatorio_posto_risco.severidade").isDifferent(null).or(
							new Field("hs_relatorio_posto_risco.valor_qualitativo_id").isDifferent(null)))) ),
				new String[]{ "hs_relatorio_posto_risco.probabilidade*hs_relatorio_posto_risco.severidade DESC" },
				null,
				null,
				null );
		array = EXECUTER.executeQuery( select );
		Vector<String> riscosVector = new Vector<String>();
		HashMap<String,Vector<Integer>> riscosIdMap = new HashMap<String,Vector<Integer>>();
		for( int n = 0; n < array.columnLength(); n++ )
		{
			Integer id = ( Integer ) array.get( n, 0 );
			String descricao = ( String ) array.get( n, 1 );
			Integer probabilidade = ( Integer ) array.get( n, 2 );
			Integer severidade = ( Integer ) array.get( n, 3 );
			String valorQualitativo = ( String ) array.get( n, 4 );
			riscos.add(
					new RiscoToPrint( 
						descricao, 
						severidade,
						probabilidade, 
						valorQualitativo, 
						getMedidasToPrintByRiscoId( id ) ) );
		}
		
		Collections.sort(riscos, new Comparator<RiscoToPrint>(){

			@Override
			public int compare(RiscoToPrint o1, RiscoToPrint o2) {
				int comparevalue = 0;				
				if (o1.probabilidade != null && o1.severidade != null
						&& o2.probabilidade != null && o2.severidade != null){
					Integer o1Value = o1.probabilidade*o1.severidade;
					Integer o2Value = o2.probabilidade*o2.severidade;
					comparevalue = 0-o1Value.compareTo(o2Value);
				} else if (o1.valorQualitativo != null
						&& o1.valorQualitativo.length() > 0
						&& o2.valorQualitativo != null
						&& o2.valorQualitativo.length() > 0) {
					if(o1.valorQualitativo.equals(CONTROLLED)){
						comparevalue = -1;
					}else if(o1.valorQualitativo.equals(INDETERMINATE)){
						comparevalue = 1;
					}else{
						if(o2.valorQualitativo.equals(CONTROLLED)){
							comparevalue = 1;
						}else{
							comparevalue = -1;
						}
					}
				}else{
					if(o1.valorQualitativo!=null){
						comparevalue = 1;
					}else{
						comparevalue = -1;
					}
				}
				return comparevalue;
				
			}
			
		});
		
		return riscos;
	}
	
	public Vector<MedidaToPrint> getMedidasToPrintByRiscoId( Integer riscoId )
		throws Exception
	{
		Vector<MedidaToPrint> medidas = new Vector<MedidaToPrint>();
		Select select = 
			new Select2(
				new String[]{ "hs_relatorio_medida" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "hs_relatorio_medida.id", "hs_relatorio_medida.requesitos_legais" },
				new Field( "hs_relatorio_medida.risco_id" ).isEqual( riscoId ).and( 
					new Field( "hs_relatorio_medida.deleted_date" ).isEqual( null ) ),
				new String[]{ "hs_relatorio_medida.id" },
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		for( int n = 0; n < array.columnLength(); n++ )
		{
			String requisitosLegais = ( String ) array.get( n, 1 );
			medidas.add( new MedidaToPrint( requisitosLegais ) );
		}
		return medidas;
	}
	
	/**
	 * Para fazer dump dos logotipos para converter para jpeg
	 */
	public Mappable[] getLogotipos()
		throws Exception
	{
		Select select = 
			new Select2( 
				new String[]{ "image" },
				new Integer[]{},
				new Expression[]{},
				new String[]{ "id", "image_data" },
				null, 
				null,
				null,
				null,
				null );
		Virtual2DArray array = EXECUTER.executeQuery( select );
		Mappable logotipos[] = new Mappable[ array.columnLength() ];
		for( int n = 0; n < logotipos.length; n++ )
		{
			Integer id = ( Integer ) array.get( n, 0 );
			byte data[] = ( byte[] ) array.get( n, 1 );
			logotipos[ n ] = 
				new MappableObject( id, data );
		}
		return logotipos;
	}
	
	/**
	 * Para fazer import dos logotipos convertidos para jpeg
	 */
	public void updateLogotipo( Integer id, byte[] data )
		throws Exception
	{
		BlobUpdate update = 
			new BlobUpdate( "image", "image_data", data, new Field( "id" ).isEqual( id ) );
		EXECUTER.executeQuery( update );
	}
}
