package siprp.planoactuacao.print;

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

import siprp.planoactuacao.db.DBConstants;
import siprp.planoactuacao.db.PlanoActuacaoDBInit;

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 PlanoActuacaoPrintDataProvider
{
	private static final Object LOCK = new Object();
	private static PlanoActuacaoPrintDataProvider instance = null;
	
	protected final Executer WEB_EXECUTER;
	protected final Executer LOCAL_EXECUTER;
	
	protected final boolean web;
	
	public PlanoActuacaoPrintDataProvider( boolean web )
		throws Exception
	{
		this.web = web;
		if( Singleton.getInstance( DBConstants.WEB_DBMANAGER ) == null )
		{
			PlanoActuacaoDBInit.initDB( web );
		}
		DBManager WEB_DBMANAGER = ( DBManager ) Singleton.getInstance( DBConstants.WEB_DBMANAGER );
		WEB_EXECUTER = WEB_DBMANAGER.getSharedExecuter( this );
		DBManager LOCAL_DBMANAGER = ( DBManager ) Singleton.getInstance( DBConstants.LOCAL_DBMANAGER );
		LOCAL_EXECUTER = LOCAL_DBMANAGER.getSharedExecuter( this );
	}
	
	public static PlanoActuacaoPrintDataProvider getProvider( boolean web )
		throws Exception
	{
		synchronized( LOCK )
		{
			if( instance == null )
			{
				instance = new PlanoActuacaoPrintDataProvider( web );
			}
		}
		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 = LOCAL_EXECUTER.executeQuery( select );
			
			return ( ( Boolean ) array.get( 0, 0 ) ).booleanValue();
		}
		catch( Exception ex )
		{
			return true;
		}
	}
	
	
	public PlanoActuacaoToPrint getPlanoToPrint( Integer id )
		throws Exception
	{
		Virtual2DArray array; 
		if( web )
		{
			Select select =
				new Select2( 
					new String[]{ "planos_actuacao" },
					new Integer[]{},
					new Expression[]{},
					new String[]{ "empresa_id", "nome_empresa", 
							"estabelecimento_id", "nome_estabelecimento", 
							"data_relatorio", "data_visita", "observacoes_dl", 
							"observacoes_dns", "validacao_director_loja", 
							"validacao_dns" },
					new Field( "id" ).isEqual( id ),
					null,
					null,
					null,
					null );
			array = WEB_EXECUTER.executeQuery( select );
		}
		else
		{
			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", 
							"estabelecimentos.id", "estabelecimentos.nome", 
							"hs_relatorio.data", "marcacoes_estabelecimento.data", "''", 
							"''", "false", 
							"false" },
					new Field( "hs_relatorio.id" ).isEqual( id ),
					null,
					null,
					null,
					null );
			array = LOCAL_EXECUTER.executeQuery( select );
		}
		Integer empresaId = ( Integer ) array.get( 0, 0 );
		String nomeEmpresa = ( String ) array.get( 0, 1 );
		Integer estabelecimentoId = ( Integer ) array.get( 0, 2 );
		String nomeEstabelecimento = ( String ) array.get( 0, 3 );
		Integer logoId = getLogotipoIdForEmpresaId( empresaId );
		Date dataRelatorio = ( Date ) array.get( 0, 4 );
		Date dataVisita = ( Date ) array.get( 0, 5 );
		String observacoesDl = ( String ) array.get( 0, 6 );
		String observacoesDns = ( String ) array.get( 0, 7 );
		Boolean validacaoDl = ( Boolean ) array.get( 0, 8 );
		Boolean validacaoDns = ( Boolean ) array.get( 0, 9 );
		EmpresaToPrint empresa = new EmpresaToPrint( nomeEmpresa,
				"http://www.evolute.pt:13080/SIPRPImages/image?id=" + logoId,
//				"http://apdp/siprp/auchan_jumbo_lado.jpg",
				nomeEstabelecimento );
		PlanoActuacaoToPrint plano = 
			new PlanoActuacaoToPrint( 
				empresa, 
				dataRelatorio != null ? new DataToPrint( "data-relatorio", dataRelatorio ) : null, 
				dataVisita != null ? new DataToPrint( "data-hs", dataVisita ) : null, 
				getLegislacaoAplicavel( id ), 
				getAreasToPrintByPlanoId( id, validacaoDl, validacaoDns ),
				observacoesDl,
				observacoesDns );
		return plano; 
	}
	
	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 = LOCAL_EXECUTER.executeQuery( select );
		return array.columnLength() > 0 ? ( Integer ) array.get( 0, 0 ) : null;
	}
	
//	public LegislacaoAplicavelToPrint getLegislacaoAplicavel( Integer planoId )
//		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( planoId ).and(
//					new Field( "hs_relatorio_legislacao.categoria" ).isEqual( null ) ),
//				null,
//				null,
//				null,
//				null );
//		Virtual2DArray array = LOCAL_EXECUTER.executeQuery( select );
//		Vector<String> diplomas = new Vector<String>();
//		for( int n = 0; n < array.columnLength(); n++ )
//		{
//			String descricao = ( String ) array.get( n, 0 );
//			diplomas.add( descricao );
//		}
//		LegislacaoAplicavelToPrint legislacao = 
//			new LegislacaoAplicavelToPrint( diplomas );
//		
//		return legislacao;
//	}
	
	public LegislacaoAplicavelToPrint getLegislacaoAplicavel( Integer planoId )
	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( planoId ),
			new String[]{ "hs_relatorio_legislacao.categoria DESC" },
			null,
			null,
			null );
	Virtual2DArray array = LOCAL_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>() );
			}
			diplomas.lastElement().add( descricao );
		}
	}
	LegislacaoAplicavelToPrint legislacao = 
		new LegislacaoAplicavelToPrint( diplomasGerais);
	return legislacao;
}
	
	public Vector<AreaToPrint> getAreasToPrintByPlanoId( Integer planoId, boolean validacaoDl, boolean validacaoDns )
		throws Exception
	{
		Virtual2DArray array;
		Vector<AreaToPrint> areas = new Vector<AreaToPrint>();
		if( web )
		{
			Select select = 
				new Select2( 
					new String[]{ "plano_areas" },
					new Integer[]{},
					new Expression[]{},
					new String[]{ "id", "descricao" },
					new Field( "plano_id" ).isEqual( planoId ),
					new String[]{ "id" },
					null,
					null,
					null );
			array = WEB_EXECUTER.executeQuery( select );
		}
		else
		{
			Select select = 
				new Select2( 
					new String[]{ "hs_relatorio_area" },
					new Integer[]{},
					new Expression[]{},
					new String[]{ "id", "description" },
					new Field( "relatorio_id" ).isEqual( planoId ).and(
						new Field( "deleted_date" ).isEqual( null ) ),
					new String[]{ "id" },
					null,
					null,
					null );
			array = LOCAL_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<RiscoToPrint> riscos = getRiscosToPrintByAreaId( areaId, validacaoDl, validacaoDns );
			if( riscos.size() > 0 )
			{
				areas.add( new AreaToPrint( areaDescricao, riscos ) );
			}
		}
		return areas;
	}
	
	public Vector<RiscoToPrint> getRiscosToPrintByAreaId( Integer areaId, boolean validacaoDl, boolean validacaoDns )
		throws Exception
	{
		Virtual2DArray array;
		Vector<RiscoToPrint> riscos = new Vector<RiscoToPrint>();
		if( web )
		{
			Select select = 
				new Select2( 
					new String[]{ "plano_riscos" },
					new Integer[]{},
					new Expression[]{},
					new String[]{ "id", "descricao", "valor", "responsavel_execucao",
							"recursos_necessarios", "data_inicio", "data_fim",
							"parecer_dl", "parecer_dns", "verificacao_siprp"},
					new Field( "area_id" ).isEqual( areaId ).and( 
						new Field( "activo" ).isEqual( "y" ) ),
					new String[]{ "id" },
					null,
					null,
					null );
			array = WEB_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 );
				Integer valor = ( Integer ) array.get( n, 2 );
				String responsavelExecucao = ( String ) array.get( n, 3 );
				String recursosNecessarios = ( String ) array.get( n, 4 );
				Date dataInicio = ( Date ) array.get( n, 5 );
				Date dataFim = ( Date ) array.get( n, 6 );
				String parecerDl = ( String ) array.get( n, 7 );
				if( ( parecerDl == null || parecerDl.trim().length() == 0 )
						&& validacaoDl )
				{
					parecerDl = "De acordo";
				}
				String parecerDns = ( String ) array.get( n, 8 );
				if( ( parecerDns == null || parecerDns.trim().length() == 0 )
						&& validacaoDns )
				{
					parecerDns = "De acordo";
				}
				String verificacaoSiprp = ( String ) array.get( n, 9 );
				riscos.add(
					new RiscoToPrint( 
						descricao, 
						valor+"",
						getMedidasToPrintByRiscoId( id ), 
						responsavelExecucao, 
						recursosNecessarios,
						dataInicio != null ? new DataToPrint( "data-prevista-inicio", dataInicio ) : null, 
						dataFim != null ? new DataToPrint( "data-prevista-conclusao", dataFim ) : null,
						parecerDl, 
						parecerDns, 
						verificacaoSiprp ) );
			}
		}
		else
		{
			Select select = 
				new Select2( 
					new String[]{ "hs_relatorio_risco", "hs_relatorio_posto_risco", "hs_relatorio_posto", "hs_relatorio_risco_valor_qualitativo" },
					new Integer[]{ Select2.JOIN_INNER, 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.posto_id" ).isEqual( new Field( "hs_relatorio_posto.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", 
							"hs_relatorio_posto.id",
							"null", 
							"null",
							"null", 
							"null", 
							"null" },
					new Field( "hs_relatorio_posto.area_id" ).isEqual( areaId ).and( 
						new Field( "hs_relatorio_risco.deleted_date" ).isEqual( null ) ).and( 
						new Field( "hs_relatorio_posto.deleted_date" ).isEqual( null ) ),
					new String[]{ "hs_relatorio_risco.id" },
					null,
					null,
					null );
			array = LOCAL_EXECUTER.executeQuery( select );
			Vector<String> riscosVector = new Vector<String>();
			HashMap<String,Vector<Integer>> riscosIdMap = new HashMap<String,Vector<Integer>>();
			HashMap<Integer,Integer> riscoPostoMap = new HashMap<Integer, Integer>();
			for( int n = 0; n < array.columnLength(); n++ )
			{
				Integer id = ( Integer ) array.get( n, 0 );
				String descricao = ( String ) array.get( n, 1 );
				Integer risco = ( Integer ) array.get( n, 2 );
				String risco_qual = ((String) array.get( n, 3));
				if(risco_qual!=null){
					risco_qual = risco_qual.substring(0, 3).toUpperCase();
				}
				Integer posto = ( Integer ) array.get( n, 4 );
				
				String finalRisco;
				
				if(risco!=null){
					finalRisco = ""+risco;
				}else if(risco_qual!=null){
					finalRisco = ""+risco_qual;
				}else{
					continue;
				}
				
				String key = descricao + "_" + finalRisco;
				if( !riscosIdMap.containsKey( key ) )
				{
					riscosIdMap.put( key, new Vector<Integer>() );
					riscosVector.add( key );
				}
				riscosIdMap.get( key ).add( id );
				riscoPostoMap.put(id, posto);
			}
			for( String risco : riscosVector )
			{
				int index = risco.lastIndexOf( "_" );
				String descricao = risco.substring( 0, index );
				String valor = risco.substring( index + 1, risco.length() ) ;
				Vector<MedidaToPrint> medidas = new Vector<MedidaToPrint>();
				for( Integer id : riscosIdMap.get( risco ) )
				{
					Integer posto = riscoPostoMap.get(id); 
					medidas.addAll( getMedidasToPrintByRiscoId( id , posto) );
				}
				if( medidas.size() > 0 )
				{
					riscos.add(
							new RiscoToPrint( 
								descricao, 
								valor,
								medidas, 
								null, 
								null,
								null, 
								null,
								null, 
								null, 
								null ) );
				}
			}
		}
		
		return riscos;
	}
	
	public Vector<MedidaToPrint> getMedidasToPrintByRiscoId( Integer riscoId) throws Exception{
		return getMedidasToPrintByRiscoId(riscoId, null);
	}
	
	public Vector<MedidaToPrint> getMedidasToPrintByRiscoId( Integer riscoId, Integer posto )
		throws Exception
	{
		Vector<MedidaToPrint> medidas = new Vector<MedidaToPrint>();
		Virtual2DArray array;
		if( web )
		{
			Select select = 
				new Select2(
					new String[]{ "plano_medidas" },
					new Integer[]{},
					new Expression[]{},
					new String[]{ "id", "descricao" },
					new Field( "risco_id" ).isEqual( riscoId ),
					new String[]{ "id" },
					null,
					null,
					null );
			array = WEB_EXECUTER.executeQuery( select );
		}
		else
		{
			Expression filter = new Field( "hs_relatorio_medida.risco_id" ).isEqual( riscoId ).and( 
					new Field( "hs_relatorio_medida.deleted_date" ).isEqual( null ) )
					.and(new Field("hs_relatorio_medida.description").isDifferent(""));
			
			if(posto!=null){
				filter = filter.and(new Field("hs_relatorio_posto_medida.posto_id").isEqual(posto));
			}
			
			Select select = 
				new Select2(
					new String[]{"hs_relatorio_medida", "hs_relatorio_posto_medida"},
					new Integer[]{Select2.JOIN_INNER},
					new Expression[]{new Field("hs_relatorio_medida.id").isEqual(new Field("hs_relatorio_posto_medida.medida_id"))},
					new String[]{ "hs_relatorio_medida.id", "hs_relatorio_medida.description", "hs_relatorio_posto_medida.is_plano_actuacao" },
					filter,
					new String[]{ "hs_relatorio_medida.id" },
					null,
					null,
					null );
			array = LOCAL_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 );
			Boolean isPlanoActuacao = ( Boolean ) array.get( n, 2 );
			Vector<PostoToPrint> postos = getPostosToPrintByMedidaId( id );
			if( postos.size() > 0 && isPlanoActuacao)
			{
				medidas.add( new MedidaToPrint(	descricao, postos ) );
			}
		}
		return medidas;
	}
	
	public Vector<PostoToPrint> getPostosToPrintByMedidaId( Integer medidaId )
		throws Exception
	{
		Vector<PostoToPrint> postos = new Vector<PostoToPrint>();
		Virtual2DArray array;
		if( web )
		{
			Select select = 
				new Select2( 
					new String[]{ "plano_postos_trabalho" },
					new Integer[]{},
					new Expression[]{},
					new String[]{ "id", "descricao" },
					new Field( "medida_id" ).isEqual( medidaId ),
					new String[]{ "id" },
					null,
					null,
					null );
			array = WEB_EXECUTER.executeQuery( select );
		}
		else
		{
			Select select = 
				new Select2( 
					new String[]{ "hs_relatorio_posto", "hs_relatorio_posto_medida" },
					new Integer[]{ Select2.JOIN_INNER },
					new Expression[]{
						new Field( "hs_relatorio_posto.id" ).isEqual( new Field( "hs_relatorio_posto_medida.posto_id" ) )
					},
					new String[]{ "hs_relatorio_posto.id", "hs_relatorio_posto.description" },
					new Field( "hs_relatorio_posto_medida.medida_id" ).isEqual( medidaId ),
					new String[]{ "hs_relatorio_posto.id" },
					null,
					null,
					null );
			array = LOCAL_EXECUTER.executeQuery( select );
		}	
		for( int n = 0; n < array.columnLength(); n++ )
		{
			String descricao = ( String ) array.get( n, 1 );
			postos.add( new PostoToPrint( descricao ) );
		}
		return postos;
	}
	
	/**
	 * 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 = LOCAL_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 ) );
		LOCAL_EXECUTER.executeQuery( update );
	}
}
