import javax.swing.*;
import java.io.*;
import java.awt.*;       
import java.awt.event.*;

//Martin Mucito Najera

public class Projecto extends JFrame implements ActionListener, WindowListener  
{
	//Este arreglo guardo los caracteres validos
	private char digit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				  			 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
							 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
							 'U', 'V', 'W', 'X', 'Y', 'Z' };
	
	//aqui inicia el programa
	public static void main (String args[])
	{
		Projecto po = new Projecto();
	}
	
	//manda llamar info
	public Projecto()
	{
		info();
	}
	
	//Variables utilizadas en info()
	private JButton bCv;
	private JButton bSm;
	private JFrame info;	
	
	//Menu de inicio de pantalla
	//en donde el usuario eligira si desea hacer conversion o
	//suma de bases
	public void info() {
		info = new JFrame();
		info.setTitle("Selecciona");
		info.setSize(200, 250);
		info.setLocation(400,200);
		info.setLayout(new FlowLayout());
		
		//boton conversion
		bCv = new JButton("Conversion entre bases");
		//boton suma
		bSm = new JButton("Suma y Resta de bases");
		
		bSm.addActionListener(this);
		bCv.addActionListener(this);
		
		info.add(bCv);
		info.add(bSm);
		info.setVisible(true);
	}
	
	//Variables para convFrame()
	private JFrame convF;
	private JButton hazlo;	
	private JLabel lInfo;
	private JLabel lIngresa;
	private JLabel Lnum;
	private JLabel Lres;
	private JTextField dBase;
	private JTextField aBase;
	private TextArea jta;
	private JTextField numero;
	private JTextField resultado;
	private Panel pan1;
	private Panel pan2;
	private Panel pan3;
	private Panel pan4;
	private Panel pan5;
	
	//Metodo de inicio de pantalla en donde
	//muestra al usuario la informacion para
	//que pueda realizar las conversiones entre bases
	public void convFrame (){
		convF = new JFrame();
		convF.setTitle("Conversion entre bases");
		convF.setSize(610, 710);
		convF.setLayout(null);
		
		hazlo = new JButton("OK");
		lInfo = new JLabel("  De Base:                    ");
		lIngresa = new JLabel("  A Base: ");
		Lnum = new JLabel("  Numero:                    ");
		Lres = new JLabel("  Resultado: ");
		
		resultado = new JTextField();
		dBase = new JTextField();
		aBase = new JTextField();
		numero = new JTextField();
		jta = new TextArea();
		pan1 = new Panel(new GridLayout());
		pan2 = new Panel(new GridLayout());
		pan3 = new Panel(new GridLayout());
		pan4 = new Panel(new GridLayout());
		pan5 = new Panel(new GridLayout());
		
		resultado.setEditable(false);
		numero.addActionListener(this);
		pan1.reshape(0,0,600,30);
		pan2.reshape(0,30,600,30);
		pan3.reshape(0,90,300,30);
		pan5.reshape(0,60,600,30);
		pan4.reshape(300,90,300,30);
		jta.reshape(0, 120, 600, 550); 
		
		pan1.add(lInfo);
		pan1.add(lIngresa);
		pan2.add(dBase);
		pan2.add(aBase);
		pan3.add(numero);
		pan5.add(Lnum);
		pan5.add(Lres);
		pan4.add(resultado);
		convF.add(pan1);
		convF.add(pan2);
		convF.add(pan3);
		convF.add(pan4);
		convF.add(pan5);
		convF.add(jta);
		
		convF.addWindowListener(this);
		convF.setVisible(true);
	}

	
	
	
	//convertir de decimal a cualquier base parte entera
	//recibe la base y el numero en decimal acepta fracciones
	public String convertirD_B(int base, float num)
	{
		int residuo  = 0;
		int cociente = (int)num;
		String s = ""; 
		boolean pflotante = false;
		if ((num - (int)num) != 0)
		{
			pflotante = true;
		}
		
		//algoritmo para resolver de decimal 
		//a cualquier base con numero entero
		while (cociente != 0)
		{
			try
			{
				imprimeD_B(cociente, base);
			} catch (Exception e) {}
			residuo  = cociente % base;
			cociente = cociente / base;
			s = digit[residuo] + s;
		}
		
		//si es fraccion
		if (pflotante)
		{
			//algortimo para resolver las partes
			//fraccionarias
			int cnt = 0;
			s = s+".";
			int pF;
			num =num - ((int)num);
			while (cnt != 4)
			{
				imprimeFD_B(base, num);
				pF = (int)(num * base);
				if (pF > 0)
				{
					num = num * base;
					num = num - pF;
				}
				num = num * base;
				s = s + pF;
				cnt++;
			}
			
		}		
		
		println("\t\t"+s);
				
		return s;
	}
	
	//metodo que imprime en el textarea de conversion
	//de bases
	public void println(String s)
	{
		try
		{
			jta.append(s+" \n");
		} catch (Exception e) {}
	}

	//imprime paso a paso lo que se hace
	public void imprimeFD_B (int base, float num2)
	{	
		//aqui se imprime a detalle como se convierte decimal a otras bases
		//la parte fraccionaria
		jta.append("\t Se multiplica: "+"\t"+num2+" por "+base+" \n");
		jta.append("\t Se guarda la parte entera: "+"\t"+(int)(base * num2)+" \n\n");
	}
	
	//imprime paso a paso lo que se hace
	public void imprimeFB_D (char digits[], int pflot[], int base)
	{	
		//aqui se imprime a detalle como se convierte de otras bases a decimal
		// la parte fraccioaria
		int j = -1;
			
		String store = "";
		double decimal = 0.0;
		jta.append("\t La fraccions se representa polinomialmente: \n");
		for (int i = 0; i < pflot.length; i++)
		{
			 decimal += pflot[(pflot.length - 1) - i] * Math.pow(base, j);
			 store   = store + "+ ( "+digits[(pflot.length - 1) - i]+"   x   "+base+"^"+j+" ) "; 
			 j--;
		}
		println("\t"+store+" \n");
		jta.append("\t Se resuelve sumando: \n");
		jta.append("\t\t"+decimal+" \n\n");
		
	}
	
	//imprime paso a paso lo que se hace
	public void imprimeD_B (int div, int base)
	{
		//se imprime a detalle como se convierte de decimal a otras bases
		try
		{
			jta.append("\t Divide: "+"\t"+div+" \n");
			jta.append("\t Entre: "+"\t"+base+" \n");
			jta.append(" \t\t"+div+" / "+base+" = "+(div/base)+" \t Sobran: "+(div%base)+" \n");
			jta.append("\t Guardando el residuo: "+" \t"+(div%base)+" \n\n");
		} catch (Exception e) {}
	}
	
	//imprime paso a paso lo que se hace
	public void imprimeB_D (char[] digits, int[] vals, int base)
	{	
		//la parte de otras bases a decimal se imprime a detalle
		try
		{
			String store = "";
			double decimal = 0.0;
			jta.append("\t Se representa polinomialmente: \n");
			for (int i = 0; i < vals.length; i++)
			{
			 	decimal += vals[(vals.length - 1) - i] * Math.pow(base, i);
			 	store   = " + ( "+digits[(vals.length - 1) - i]+"   x   "+base+"^"+i+" )"+store ; 
			}
			println("\t"+store+" \n");
			jta.append("\t Se resuelve sumando: \n");
			jta.append("\t\t"+decimal+" \n\n");
		}catch (Exception e) {}		
	}
	
	//convertir de cualquier base a decimal parte entera
	public float convertirB_D (int base, char[] num) 
	{
		int cont = num.length;
		for (int i = 0; i < num.length; i++)
		{
			if (num[i] == '.')
			{
				cont = i;
				break;
			}
		}
		
		int vals[] = new int[cont];
		float decimal = 0.0f;
	
		//algoritmo para conseguir los valores de
		//la letras en bases mayores a 10
		for (int i = 0; i < vals.length; i++) {
			for (int j = 0; j < base; j++) {
				if (num[i] == digit[j])	{
					vals[i] = j;
					break;
				}
				else if (j == (base - 1))
				{
					JOptionPane.showMessageDialog(this, "Error en los digitos permitidos");
					return 0.0f;
				}
			}
		}
		
		if (base != 10)
		{
			println("\t\t Conviertes a decimal: \n");
			imprimeB_D(num, vals, base);
		}
		
		for (int i = 0; i < vals.length; i++)
		{
			decimal += vals[(vals.length - 1) - i] * Math.pow(base, i); 
		}
		
		//algortimo para resolver la conversion de otras bases a decimal
		//partes fraccionarias
		if (cont < num.length)
		{
			int pflot[] = new int[(num.length-1)-cont];
			char dig[] = new char[(num.length-1)-cont];
			int intcnt = 0;
			for (int i = (num.length -1); i >= (cont+1); i--) {
				for (int j = 0; j < base; j++) {
					if (num[i] == digit[j])	{
						dig[intcnt] = num[i];
						pflot[intcnt] = j;
						break;
					}
					else if (num[i] == '.')
					{
						break;
					}
					else if (j == (base - 1))
					{
						JOptionPane.showMessageDialog(this, "Error en los digitos permitidos");
						return 0.0f;
					}
				}
				intcnt++;
			}	
		
			int j = -1;
			
			for (int i = 0; i < pflot.length; i++)
			{
				decimal += pflot[(pflot.length - 1) - i] * Math.pow(base, j);
				j--;
			}
			
			if (base != 10)
			{
				println("\t\t Conviertes la fraccion a decimal: \n");
				imprimeFB_D(dig, pflot, base);
			}	
		}
		return decimal;
	}
	
	// aqui dentro se realizan todas las operaciones del programa.
	// y la captura de eventos
	public void actionPerformed (ActionEvent e) {
		if (e.getSource() == bSm) {
			info.setVisible(false);
			sumaFrame();
		}
		
		
		if (e.getSource() == bCv) {
			convFrame();
			info.setVisible(false);
		}
		
		if (e.getSource() == numero) {
			jta.setText("");
			try
			{
				
				int dbase = Integer.parseInt(dBase.getText());
				int abase = Integer.parseInt(aBase.getText());
				if (dbase > 1 && abase > 1)
					resultado.setText(convertirD_B(abase, convertirB_D(dbase, numero.getText().toCharArray())));
			} catch (NumberFormatException nfe) {
				JOptionPane.showMessageDialog(this, "De base y A base tienen que tener un valor en decimal!");
				dBase.setText("");
				aBase.setText("");
			}
		}
		
		if (e.getSource() == numero2 || e.getSource() == resultado2)
		{
			jta2.setText("");
			try
			{
				int dbase1 = Integer.parseInt(dBase1.getText());
				int dbase2 = Integer.parseInt(dBase2.getText());
				int abase2 = Integer.parseInt(aBase2.getText());
				if (dbase1 > 1 && abase2 > 1 && dbase2 > 1)
				{
					String resta = resultado2.getText().substring(1);
					if (resultado2.getText().indexOf("-") < 0)
					{
						String operando1 = convertirD_B(abase2, convertirB_D(dbase1, numero2.getText().toCharArray()));
						String operando2 = convertirD_B(abase2, convertirB_D(dbase2, resultado2.getText().toCharArray()));
						if (operando1.length() >= operando2.length())
						{
							for (int i = operando2.length(); i < operando1.length(); i++)
							{
								operando2 = "0"+operando2;
							}
						}
						else
						{
							for (int i = operando1.length(); i < operando2.length(); i++)
							{
								operando1 = "0"+operando1;
							}
							
						}
						
						suma(operando1.toCharArray(), operando2.toCharArray(), abase2);
					}
					else
					{
						String operando1 = convertirD_B(abase2, convertirB_D(dbase1, numero2.getText().toCharArray()));
						String operando2 = convertirD_B(abase2, convertirB_D(dbase2, resta.toCharArray()));
						if (operando1.length() >= operando2.length())
						{
							for (int i = operando2.length(); i < operando1.length(); i++)
							{
								operando2 = "0"+operando2;
							}
						}
						else
						{
							for (int i = operando1.length(); i < operando2.length(); i++)
							{
								operando1 = "0"+operando1;
							}
							
						}
						
						suma2(operando1.toCharArray(), operando2.toCharArray(), abase2);
					}
				}
			} catch (NumberFormatException nfe) {
				JOptionPane.showMessageDialog(this, "Base 1, base 2, y a base tienen que tener un valor en decimal!");
				dBase1.setText("");
				dBase2.setText("");
				aBase2.setText("");
			}
		}
	
	}
	
	public void windowActivated (WindowEvent e){}
	
	public void windowDeactivated (WindowEvent e){}
	
	//Al recibir este evento el programa termina.
	public void windowClosing (WindowEvent e){System.exit(0);}
	
	public void windowClosed (WindowEvent e){}
	
	public void windowDeiconified (WindowEvent e){}
	
	public void windowIconified (WindowEvent e){}
	
	public void windowOpened (WindowEvent e){}


	//Variables para suma entre bases
	private JFrame sumaF;
	private JLabel lInfo1;
	private JLabel lInfo2;
	private JLabel lIngresa2;
	private JLabel Lnum2;
	private JLabel Lres2;
	
	private JTextField dBase2;
	private JTextField dBase1;
	private JTextField aBase2;
	private TextArea jta2;
	private JTextField numero2;
	private JTextField resultado2;
	private Panel pan12;
	private Panel pan22;
	private Panel pan32;
	private Panel pan42;
	private Panel pan52;
	
	//Metodo de inicio de pantalla para Suma entre bases
	public void sumaFrame (){
		sumaF = new JFrame();
		sumaF.setTitle("Suma y resta entre bases");
		sumaF.setSize(610, 710);
		sumaF.setLayout(null);
		//base del primer numero
		lInfo1 = new JLabel("  Base:                    ");
		//base del segundo numero
		lInfo2 = new JLabel("  Base:                    ");
		//a la base que se desea
		lIngresa2 = new JLabel("  A Base: ");
		//el numero 1
		Lnum2 = new JLabel("  Numero 1:                    ");
		//el numero 2
		Lres2 = new JLabel("  Numero 2: ");
		
		resultado2 = new JTextField();
		dBase1 = new JTextField();
		dBase2 = new JTextField();
		aBase2 = new JTextField();
		numero2 = new JTextField();
		jta2 = new TextArea();
		pan12 = new Panel(new GridLayout());
		pan22= new Panel(new GridLayout());
		pan32 = new Panel(new GridLayout());
		pan42 = new Panel(new GridLayout());
		pan52 = new Panel(new GridLayout());
		
		numero2.addActionListener(this);
		resultado2.addActionListener(this);
		pan12.reshape(0,0,600,30);
		pan22.reshape(0,30,600,30);
		pan32.reshape(0,90,300,30);
		pan52.reshape(0,60,600,30);
		pan42.reshape(300,90,300,30);
		jta2.reshape(0, 120, 600, 550); 
		
		pan12.add(lInfo1);
		pan12.add(lInfo2);
		pan12.add(lIngresa2);
		pan22.add(dBase1);
		pan22.add(dBase2);
		pan22.add(aBase2);
		pan32.add(numero2);
		pan52.add(Lnum2);
		pan52.add(Lres2);
		pan42.add(resultado2);
		sumaF.add(pan12);
		sumaF.add(pan22);
		sumaF.add(pan32);
		sumaF.add(pan42);
		sumaF.add(pan52);
		sumaF.add(jta2);
		
		sumaF.addWindowListener(this);
		sumaF.setVisible(true);
	}

	//length de ambos arreglos tiene que ser igual
	//se verifica en el actionListener antes de mandar los valores
	//metodo para sumar dos bases
	public void suma(char c[], char[] c2, int base1)
	{
	
		int length = c.length;
		
		char[] car = new char[(length+1)];
		
		int val[]  = new int[length];
		int val2[] = new int[length];
		char sumado[] = new char[length+1];
		int carry = 0;
		
		//para el primero se obtiene los valores de las letras
		for (int i = 0; i < length; i++) {
			for (int j = 0; j < base1; j++) {
				if (c[i] == digit[j])	{
					val[i] = j;
					break;
				}
				else if (j == (base1 - 1))
				{
					JOptionPane.showMessageDialog(this, "Error en los digitos permitidos");
				}
			}
		}
		
		//para el segundo se obtiene los valores de las letras
		for (int i = 0; i < length; i++) {
			for (int j = 0; j < base1; j++) {
				if (c2[i] == digit[j])	{
					val2[i] = j;
					break;
				}
				else if (j == (base1 - 1))
				{
					JOptionPane.showMessageDialog(this, "Error en los digitos permitidos");
				}
			}
		}		
		
		for (int i  = 0; i < car.length; i++)
			car[i] = ' ';
			
		int suma = 0;
		//aqui ya hago la suma y guardo carry
		for (int i = 0; i < length; i++)
		{
			suma = 0;
			suma = val[(length - 1) - i] + val2[(length - 1) - i] + carry;
			//no carry
			if (suma < base1)
			{
				sumado[length - i] = digit[suma];
				carry = 0;
				car[(car.length - 1) - (i+1)] = ' ';
			}
			//si hay carry
			else
			{
				suma = suma - base1;
				carry = 1;
				car[(car.length - 1) - (i+1)] = '1';
				sumado[length - i] = digit[suma];
			}
		}
		
		sumado[0] = digit[carry];
		
		
		String s1 = new String(car);
		String s2 = new String(c);
		String s3 = new String(c2);
		String s4 = new String(sumado);
		
		println2("\t\t"+s1);
		println2("\t\t0"+s2);
		println2("\t+\t0"+s3);
		println2("\t\t_____________");
		println2("\t\t"+s4);
	
	}

	//length de ambos arreglos tiene que ser igual
	//se verifica en el actionListener antes de mandar los valores
	//metodo para restar dos bases

	public void suma2(char c[], char[] c2, int base1)
	{
	
		int length = c.length;
	