package webCAPPCombd;

import comHttp.RequisitorHttp;
import infoUsinagem.*;
import java.util.StringTokenizer;
import java.util.Properties;

/**
 * Classe que fornece métodos para determinação das condições de usinagem para
 * cada tipo de usinagem.
 *
 * @author Marcos V. S. Godinho
 * @version 1.0
 */
public class DeterminadorDeTecUsinagem{

  private static final String URI_DO_SERVLET = ":8080/combdServlet/comhttpservlet";
  private static final String URL_DOS_DADOS = "http://www.coroguide.com/CuttingDataModule/CDMTurning.asp";


  //Constantes de tipo de pastilha usada em torneamento.
  public static final int TG_PASTILHA_COMUM = 0;
  public static final int TG_PASTILHA_REDONDA = 1;
  //Constantes de tipo de torneamento.
  public static final int TG_ACABAMENTO_EXTREMO = 0;
  public static final int TG_ACABAMENTO = 1;
  public static final int TG_USINAGEM_MEDIA = 2;
  public static final int TG_DESBASTE_LEVE = 3;
  public static final int TG_DESBASTE = 4;
  public static final int TG_DESBASTE_PESADO = 5;
  //Constante de valores fixos.
  private static final String TG_PADRAO_VALOR = "AISI/SAE";
  private static final String TG_UNIDADES_VALOR = "0";///padrão métrico.
  private static final String TG_COMANDO_DE_CALCULO_VALOR = "Calculate";
  //Variáveis fixas.
  private static final String TG_PADRAO = "cboMtrlstnd";
  private static final String TG_UNIDADES = "optMetric";
  private static final String TG_COMANDO_DE_CALCULO = "cmdCalc";
  //Constante dos nomes das variáveis.
  private static final String TG_TIPO_PASTILHA = "optTurning";
  private static final String TG_TIPO_TORNEAMENTO = "optType";
  private static final String TG_MATERIAL = "cboMaterial";
  private static final String TG_CLASSE = "cboGrade";
  private static final String TG_Kr_OU_IC = "txtKriC";
  private static final String TG_RAIO_PONTA = "txtre";
  private static final String TG_AVANCO = "txtfn";
  private static final String TG_PROFUNDIDADE_CORTE = "txtap";
  private static final String TG_Dm1 = "txtdmin";
  private static final String TG_Dm2 = "txtdmax";
  private static final String TG_Lz = "txtlz";
  private static final String TG_MAX_RPM = "txtMaxn";
  private static final String TG_TEMPO_VIDA = "txtt";
  //Constantes das variaveis de retorno.
  private static final String TG_VC = "lblVcStartStop";
  private static final String TG_RPM = "lbln";
  private static final String TG_TAXA_REMOCAO = "lblQ";
  private static final String TG_NUM_PASSES = "txtnap";
  private static final String TG_TEMPO_PASSE = "lblTc";
  private static final String TG_POTENCIA = "lblPc";
  private static final String TG_RUGOSIDADE = "lblRa";

  private RequisitorHttp requisitor;

  public DeterminadorDeTecUsinagem(String urlDoServidor){

    requisitor =  new RequisitorHttp(urlDoServidor + URI_DO_SERVLET);
  }


  //Calcula uma única condição de usinagem qualquer.
  private final TecnologiaDeUsinagem calculaCondicaoDeUsinagem(
    int tipoPastilha, int tipoTorneamento,
    String material, FerramentaTorneamento f,
    double ap, double fn, double dm1, double dm2, double lz, int maxRPM, int tempoVida){

    Properties prop = new Properties();
    //fixas.
    prop.setProperty(TG_PADRAO, TG_PADRAO_VALOR);
    prop.setProperty(TG_UNIDADES, TG_UNIDADES_VALOR);
    prop.setProperty(TG_COMANDO_DE_CALCULO, TG_COMANDO_DE_CALCULO_VALOR);
    //variaveis.
    prop.setProperty(TG_TIPO_PASTILHA, String.valueOf(tipoPastilha));
    prop.setProperty(TG_TIPO_TORNEAMENTO, String.valueOf(tipoTorneamento));
    prop.setProperty(TG_MATERIAL, material);
    prop.setProperty(TG_CLASSE, f.getClasse());
    if(tipoPastilha == TG_PASTILHA_COMUM){
      //Busca o angulo Kr(cut_out).
      prop.setProperty(TG_Kr_OU_IC, String.valueOf(f.getCutOut()));
      prop.setProperty(TG_RAIO_PONTA, String.valueOf(f.getRaioPonta()));
    }
    else{//Busca o diametro da ferramenta redonda.
      prop.setProperty(TG_Kr_OU_IC, String.valueOf(f.getCompArestaDeCorte()));
    }
    prop.setProperty(TG_AVANCO, String.valueOf(fn));
    prop.setProperty(TG_PROFUNDIDADE_CORTE, String.valueOf(ap));
    prop.setProperty(TG_Dm1, String.valueOf(dm1));
    prop.setProperty(TG_Dm2, String.valueOf(dm2));
    prop.setProperty(TG_Lz, String.valueOf(lz));
    prop.setProperty(TG_MAX_RPM, String.valueOf(maxRPM));
    prop.setProperty(TG_TEMPO_VIDA, String.valueOf(tempoVida));

    Properties resposta = requisitor.requisitaHttpVars(URL_DOS_DADOS, prop);

    StringTokenizer strVc = new StringTokenizer(resposta.getProperty(TG_VC), " -");
    StringTokenizer strRPM = new StringTokenizer(resposta.getProperty(TG_RPM), " -");

    return new TecnologiaDeUsinagem(ap, fn,
                                    strVc.hasMoreTokens() ? strVc.nextToken(): null,//vc_max
                                    strVc.hasMoreTokens() ? strVc.nextToken(): null,
                                    strRPM.hasMoreTokens() ? strRPM.nextToken(): null,//RPM_max
                                    strRPM.hasMoreTokens() ? strRPM.nextToken(): null,
                                    resposta.getProperty(TG_TAXA_REMOCAO),
                                    resposta.getProperty(TG_NUM_PASSES),
                                    resposta.getProperty(TG_TEMPO_PASSE),
                                    resposta.getProperty(TG_POTENCIA),
                                    resposta.getProperty(TG_RUGOSIDADE)
                                    );
  }//calculaCondicaoDeUsinagem


  //Calcula todas as condições de usinagem para uma dada ferramenta.
  //Reparte a longa busca de dados via HTTP em multithreading.
  private TecnologiaDeUsinagem[] calculaArrayTecnologiaDeUsinagem(final int tipoTorneamento,
    final String material, final Ferramenta f, final double dm1, final double dm2,
    final double lz, final int maxRPM, final int tempoVida, final CalculoDeRestricao calc){

    final FerramentaTorneamento ferramenta = f instanceof FerramentaUtilizada ?
        (FerramentaTorneamento)((FerramentaUtilizada)f).getFerramenta() :
        (FerramentaTorneamento)f;

    final int tipoPastilha;
    switch(ferramenta.getFormatoPastilha()){//pega o tipo de pastilha.

      case 'R': case 'r':
        tipoPastilha = this.TG_PASTILHA_REDONDA; break;

      case 'C': case 'c':
      case 'D': case 'd':
      case 'K': case 'k':
      case 'S': case 's':
      case 'T': case 't':
      case 'V': case 'v':
      case 'W': case 'w':
        tipoPastilha = TG_PASTILHA_COMUM; break;

      default:
        throw new RuntimeException("Tipo de pastilha inválido da ferramenta:" + f);
    }

    int i;
    double ap;
    final TecnologiaDeUsinagem[]  arrayTec=//Calcula tamanho do array necessário.
        new TecnologiaDeUsinagem[(int)((ferramenta.getMax_ap()-ferramenta.getMin_ap())/0.1)];

    final Contador contador = new Contador();

    for(i=0, ap = ferramenta.getMin_ap(); i < arrayTec.length; i++, ap+= 0.1){

      final int iAtual = i;
      final double apAtual = ap;

      new java.lang.Thread(){

        double fn = ferramenta.getMax_fn();
        double ap = apAtual;
        int i = iAtual;
        TecnologiaDeUsinagem temp = null;

        public void run(){

          do {

            temp = calculaCondicaoDeUsinagem(tipoPastilha,
                tipoTorneamento, material, ferramenta,
                ap, fn, dm1, dm2, lz, maxRPM, tempoVida);

            fn -= 0.1;
          }
          while ( (temp == null || !calc.restricaoSatisfeita(temp)) &&
                 fn > ferramenta.getMin_fn());

          arrayTec[i] = temp;

          contador.incrementa();
          synchronized(contador){
            contador.notify();
          }

        }
      }.start();
    }

    while(contador.getValor() <  arrayTec.length){

      try{
        synchronized(contador){
          contador.wait();
        }
      }
      catch(InterruptedException e){}
    }

    return arrayTec;
  }//calculaArrayTecnologiaDeUsinagem


  //Todos métodos calculistas de condição de usinagem diversos e específicos vem abaixo.


  public TecnologiaDeUsinagem[] calculaCondicaoDeUsinagem_TorneamentoDesbaste(int tipoTorneamento,
    String material, Ferramenta f, double dm1, double dm2,
    double lz, int maxRPM, int tempoVida, final double potenciaMaxima){

    CalculoDeRestricao calc = new CalculoDeRestricao(){

        public boolean restricaoSatisfeita(TecnologiaDeUsinagem tec){

          return tec.getPotencia() < potenciaMaxima;
        }
    };

    return calculaArrayTecnologiaDeUsinagem(tipoTorneamento, material, f, dm1, dm2, lz,
                                   maxRPM, tempoVida, calc);
  }


  public TecnologiaDeUsinagem[] calculaCondicaoDeUsinagem_TorneamentoAcabamento(int tipoTorneamento,
    String material, Ferramenta f, double dm1, double dm2,
    double lz, int maxRPM, int tempoVida, final double rugosidadeMaxima){

    CalculoDeRestricao calc = new CalculoDeRestricao(){

        public boolean restricaoSatisfeita(TecnologiaDeUsinagem tec){

          return tec.getRugosidade() < rugosidadeMaxima;
        }
    };

    return calculaArrayTecnologiaDeUsinagem(tipoTorneamento, material, f, dm1, dm2, lz,
                                   maxRPM, tempoVida, calc);
  }
}


/**
 * Classe utilizada para a contagem sincronizada entre as Threads que
 * que repartem o trabalho de busca da condição de usinagem.
 *
 * @author Marcos V. S. Godinho
 * @version 1.0
 */
class Contador{

  int i = 0;

  synchronized void incrementa(){

    i++;
  }

  int getValor(){

    return i;
  }
}
