/**
 * 
 */
package parser;

import java.util.List;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.ListIterator;
import java.util.Scanner;

import databases.DatabasePronomi;
import databases.DatabaseVerbi;

import types.*;


/**
 * @author Giorgio Ravera
 *
 */
public class Parser 
{
	private Scanner read = new Scanner(System.in);
	private LinkedHashMap<String, Symbol> dictionary = new LinkedHashMap<String,Symbol>();
	
	private DatabasePronomi pronomi = DatabasePronomi.getInstance();
	private DatabaseVerbi dbverbi = DatabaseVerbi.getInstance();
	
	// Verbi Ausiliari
	private Verbo avere = new Verbo("avere");
	private Verbo essere = new Verbo("essere");

	private List<Symbol> frase = new LinkedList<Symbol>();
	
	/**
	 * Costruttore: inizializza il dizionario
	 *
	 */
	public Parser()
	{
		// Inserimento Pronomi
		dictionary.put("io", new Pronome("io", Persona.io));
		dictionary.put("me", new Pronome("me", Persona.io, true));
		dictionary.put("mi", new Pronome("mi", Persona.io, true));
		
		dictionary.put("tu", new Pronome("tu", Persona.tu));
		dictionary.put("te", new Pronome("te", Persona.tu, true));
		dictionary.put("ti", new Pronome("ti", Persona.tu, true));
		
		dictionary.put("lui", new Pronome("lui", Persona.egli));
		dictionary.put("egli", new Pronome("egli", Persona.egli));
		dictionary.put("gli", new Pronome("gli", Persona.egli, true));
		
		dictionary.put("lei", new Pronome("lei", Persona.egli));
		dictionary.put("le", new Pronome("le", Persona.egli, true));
		
		dictionary.put("noi", new Pronome("noi", Persona.noi));
		dictionary.put("ci", new Pronome("ci", Persona.voi, true));
		
		dictionary.put("voi", new Pronome("voi", Persona.voi));
		dictionary.put("vi", new Pronome("vi", Persona.voi, true));
		
		dictionary.put("essi", new Pronome("essi", Persona.essi));
		dictionary.put("esse", new Pronome("esse", Persona.essi));
		dictionary.put("loro", new Pronome("loro", Persona.essi));

		// Inserimento Articoli
		dictionary.put("il", new Articolo("il"));
		dictionary.put("lo", new Articolo("lo"));
		dictionary.put("la", new Articolo("la"));
		dictionary.put("i", new Articolo("i"));
		dictionary.put("gli", new Articolo("gli"));
		dictionary.put("le", new Articolo("le"));
		dictionary.put("l'", new Articolo("l'"));
		dictionary.put("un", new Articolo("un"));
		dictionary.put("uno", new Articolo("uno"));
		dictionary.put("una", new Articolo("una"));
		dictionary.put("un'", new Articolo("un'"));
		
		// Verbo Avere
		dictionary.put("avere", avere);
		avere.addVerboConiugato("ho", TempoVerbale.presente, Persona.io);
		avere.addVerboConiugato("hai", TempoVerbale.presente, Persona.tu);
		avere.addVerboConiugato("ha", TempoVerbale.presente, Persona.egli);
		avere.addVerboConiugato("abbiamo", TempoVerbale.presente, Persona.noi);
		avere.addVerboConiugato("avete", TempoVerbale.presente, Persona.voi);
		avere.addVerboConiugato("hanno", TempoVerbale.presente, Persona.essi);

		// Verbo Essere
		dictionary.put("essere", essere);
		essere.addVerboConiugato("sono", TempoVerbale.presente, Persona.io);
		essere.addVerboConiugato("sei", TempoVerbale.presente, Persona.tu);
		essere.addVerboConiugato("", TempoVerbale.presente, Persona.egli);
		essere.addVerboConiugato("siamo", TempoVerbale.presente, Persona.noi);
		essere.addVerboConiugato("siete", TempoVerbale.presente, Persona.voi);
		//essere.addVerboConiugato("sono", TempoVerbale.presente, Persona.essi);
	}
	
	/**
	 * Funzione che da il via all'analisi sintattica.<br />Questa viene effettuata una parola alla volta.
	 */
	public Frase nextFrase()
	{
		Symbol s=null;
		while(read.hasNext())
		{
			s = nextSymbol();
			if(s.getValore().equals("#"))
			{
				mostraFrase();
				return elaboraFrase();
			}
			else if(s.getValore().equals("exit"))
			{
				return null;
			}
			else
			{
				if(s.getType()==Type.articolo)
					System.out.println("Articolo, salto");
				else
					frase.add(s);
			}
		}
		return null;
	}
	
	/**
	 * 
	 * @return
	 */
	public Symbol nextSymbol()
	{
		String s = null;
		s = read.next();
		System.out.println(s);
		
		//usato per essere e avere
		VerboConiugato Temp = null;
		
		Symbol sy = dictionary.get(s);
		if(sy!=null)
		{
			System.out.println("Trovato " + sy.getType() + " " + (sy.getClass()).toString());
			// Se trovo infinito devo avere un verbo coniugato per l'analisi
			if(sy instanceof Verbo)
				sy = dbverbi.find(sy.getValore()); 
			
			// C' quindi so cosa sia.
		}

		if(sy==null)
		{
			System.out.println("Non in memoria principale");
			sy=Verbo.castVerbo(s);
			if(sy!=null)
			{
				if(sy.getClass().equals(VerboConiugato.class))
				{
					if(((VerboConiugato)sy).getVerbo().equals(essere) || ((VerboConiugato)sy).getVerbo().equals(avere))
					{
						System.out.println("Deriva da essere o avere");
						Temp = (VerboConiugato) sy;
						s = read.next();
						sy = dictionary.get(s);
						// Se non trova potrebbe essere verbo						
						if(sy==null)
						{
							sy=Verbo.castVerbo(s);
							if(sy!=null && ((VerboConiugato)sy).getPersona()==Persona.nussuna)
							{
								System.out.println("ho vinto  un verbo");
								VerboConiugato vc = (VerboConiugato)sy;
								sy = vc.getVerbo().addVerboConiugato(Temp.getValore() + " " + vc.getValore(), Temp.getTempo(),Temp.getPersona());
								vc = (VerboConiugato)sy;
								System.out.println(vc.getValore() + " " + vc.getTempo() + " " + vc.getPersona());
								// AGGIUNGERE TERZA FORMA: SONO STATO MANGIATO
							}
							else
							{
								//Cerco su coso di verbi
								System.out.println("aggiungo in lista Temp e procedo perch so che non  un verbo oppure  un altro");
								frase.add(Temp);
							}
						}
						// Se lo trova allora si sa che non  un verbo (troverebbe forma infinita che non  coniugabile)
						else
						{
							System.out.println("aggiungo in lista Temp e procedo perch so che non  un verbo.");
							frase.add(Temp);
							if(sy instanceof Verbo)
								sy = dbverbi.find(sy.getValore()); 
						}
					}
				}
			}
			if(sy==null)
			{
				//Cerco su sito coniuga.com e verifico se non lo  davvero
				sy=Numero.castNumber(s);
				if(sy==null)
					sy=find(s);//Cerca su google?
			}
			System.out.println("Trovato " + sy.getType() + " " + (sy.getClass()).toString());
			//I verbi li aggiungo solo all'infinito
			if(sy.getClass()==VerboConiugato.class)
			{
				VerboConiugato v = (VerboConiugato)sy;
				Verbo verbo = v.getVerbo();
				//sbatto dentro tutte le coniugazioni prese da sito assurdo
				s = verbo.getValore();
				if(!dictionary.containsKey(s))
				{
					System.out.println("Metto Infinito di " + sy.getValore() + ": " + verbo.getValore());
					dictionary.put(s, verbo);
				}
			}
			else
			{
				System.out.print("Aggiungo!!");
				dictionary.put(s, sy);
			}
		}
		return sy;
	}
	
	/**
	 * Cerca su google o similari che cosa sia il simbolo appena rilevato che non appartiene al proprio dizionario.
	 */
	private Symbol find(String s)
	{
		//cerca su google e ottiene un id;
		int id=1;
		Symbol simbolo = null;
		switch(id)
		{
			case 1:
			{
				simbolo = new Word(s);
				break;
			}
			/*
			 case 6:
			{
				simbolo = new Numero(s);
				break;
			}
			*/
		}
		return simbolo;
	}
	
	
	public void mostraFrase()
	{
		System.out.println("Frase corrente: ");
		ListIterator<Symbol> li = (ListIterator<Symbol>) frase.iterator();
		int i = 1;
		Symbol s= null;
		while(li.hasNext())
		{
			s = li.next();
			System.out.println(i++ + ": " + s.getValore() + " " + s.getClass().toString() + " " + s.getType() + "\n\n");
		}
	}	
	
	public Frase elaboraFrase()
	{
		System.out.println("Elaboro la frase");
		
		Symbol soggetto =null;
		VerboConiugato verbo=null;
		Symbol oggetto=null;
		
		Symbol s = null;
		List<Symbol> pre_verbo = new LinkedList<Symbol>();
		List<Symbol> post_verbo = new LinkedList<Symbol>();
		
		// Cerca il verbo
		ListIterator<Symbol> li = (ListIterator<Symbol>) frase.iterator();
		while(li.hasNext())
		{
			s = li.next();
			if(s.getType()==Type.verbo && verbo == null)
			{
				li.remove();
				verbo = (VerboConiugato)s;
				//System.out.println("trovato verbo: "+ verbo.getValore() + " " + verbo.getPersona());
				continue;
			}
			if(verbo==null)
				pre_verbo.add(s);
			else
				post_verbo.add(s);
		}
		
		//suppongo ci sia sempre un verbo. come gestire esclamazioni del tipo: CHE FAME?
		if(verbo==null)
			return null;
		
		// Cerca il soggetto o oggetto.
		li = (ListIterator<Symbol>) frase.iterator();
		boolean passive=false;
		while(li.hasNext())
		{
			s = li.next();
			if(s.getType()==Type.pronome)
			{
				Pronome p = (Pronome)s;
				if(p.getPersona()==verbo.getPersona() && !p.isPassive())
				{
					//System.out.println("trovato soggetto: "+ s.getValore());
					soggetto = p;
					li.remove();
					break;
				}
				else if(verbo.getPersona()>3 && !p.isPassive())
				{
					if(li.hasNext())
					{
						soggetto = p;
						s = li.next();
						if(s.getValore().equals("e"))
						{
							System.out.println("1 Multiplo!!!!!!!!!!!!!");
							li.remove();
							break;
						}
						else 
							soggetto = null;
					}
				}
				if(p.isPassive())
				{
					//System.out.println("trovato oggetto: "+ s.getValore());
					oggetto = p;
					passive=true;
					li.remove();
					if(li.hasNext())
					{
						s=li.next();
						if(s.getValore().equals("e"))
						{
							System.out.println("2 Multiplo!!!!!!!!!!!!!");
							li.remove();
						}
					}
					break;
				}
			}
		}
		
		
			
		if(frase.size()!=0)
		{
			// se non c' il soggetto vuol dire che  di terza persona. itero fino al verbo e se trovo parola quella  soggetto.
			if(soggetto==null && (verbo.getPersona()==Persona.egli ||verbo.getPersona()==Persona.essi) )
			{
				if(passive)
					li = (ListIterator<Symbol>) post_verbo.iterator();
				else
					li = (ListIterator<Symbol>) pre_verbo.iterator();
				while(li.hasNext())
				{
					s=li.next();
					if(s.getType()==Type.parola)
					{
						soggetto = s;
						li.remove();
						
						if(li.hasNext())
						{
							s = li.next();
							if(s.getValore().equals("e"))
							{
								System.out.println("3 Multiplo!!!!!!!!!!!!!");
								li.remove();
								break;
							}
						}
						
						break;
					}
				}
			}
			
			// se non c' l'oggetto la prima parola  l'oggetto.
			if(oggetto==null)
			{
				if(!passive)
					li = (ListIterator<Symbol>) post_verbo.iterator();
				else
					li = (ListIterator<Symbol>) pre_verbo.iterator();
				while(li.hasNext())
				{
					s=li.next();
					if(s.getType()==Type.parola)
					{
						oggetto = s;
						li.remove();
						
						if(li.hasNext())
						{
							s = li.next();
							if(s.getValore().equals("e"))
							{
								System.out.println("4 Multiplo!!!!!!!!!!!!!");
								li.remove();
								break;
							}
						}						
						
						break;
					}
				}
			}
		}
		else
		{
			
			//calcolo soggetto da verbo
		}
		if(frase.size()!=0)
		{
			System.out.println("altra roba che non capisco nella frase, me ne fotto");
			// se non c' ancora il soggetto lo ricavo dal verbo.
		}
		
		System.out.println("Ok, ho capito");
		System.out.println("prima di verbo: " + pre_verbo.size());
		System.out.println("dopo di verbo: " + post_verbo.size());

		
		frase.clear();		
		
		return new Frase(soggetto, verbo, oggetto);		
	}
}