import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

// N'oubliez pas qu'en Java il faut respecter les minuscules/MAJUSCULES.

/**
 * Classe principale de la mobilette, celle-ci calcule la consommation
 * d'un véhicule à partir de son kilométrage et de la quantité d'essence.<br>
 * Comme c'est une mobilette, c'est une classe dérivée de Midlet.<br>
 * Cette classe implémente les interfaces suivantes (elle définit les
 * méthodes de ces interfaces) :<ul>
 * <li>ItemStateListener pour être informé dès que le contenu des zones de
 * saisies (TextField) est modifié par l'utilisateur. Ainsi nous pouvons
 * mettre à jour le texte consommationSI sans action spéciale de l'utilisateur.
 * Attention, sur certains téléphones l'usage des ItemStateListener n'est pas
 * parfait : pour que la consommation soit prise en compte après saisie,
 * l'utilisateur doit aller sur le kilométrage pur que le télphone appelle
 * le listener. Ca ne conerne que quelques modèles, mais du coup il faut
 * considérer que l'ItemStateListener est seulement un plus, la façon "normale"
 * étant d'utiliser un CommandListener.   
 * <li>CommandListener pour être informé quand l'utilisateur choisit une
 * des commandes que nous avons ajouté à l'écran (calcul et quitter).
 * </ul>
 * 
 * @author Thibaut REGNIER, mobilette@club-java.com
 */
public class EcoLogic
	extends MIDlet
	implements ItemStateListener, CommandListener
{
	/**
	 * Ecran sur lequel la mobilette est affichée.<br>
	 * Vaut null au lancement (car non affectée), sera initialisée par notre
	 * code lors du premier appel à startApp() par le système.<br>
	 * Attention! display ne pourrait pas être initialisée dans
	 * le constructeur de la classe, l'écran n'étant défini par le système
	 * qu'à partir du moment où startApp() est appelée pour la première fois.
	 * N'oubliez pas que certains téléphones ont 2 écrans
	 * (ex:Nokia Communicator) et le système décide au lancement sur quel
	 * écran on sera affiché.
	 */
	private Display display;

	/**
	 * Formulaire affiché à l'écran contenant les textes et zones de saisies.
	 */
	private Form formulaire;

	/**
	 * Zone de saisie contenant le nombre de kilomètres parcourus.
	 */
	private TextField kilometrageTF;

	/**
	 * Zone de saisie contenant le nombre de litres d'essence consommés.
	 */
	private TextField litresEssenceTF;

	/**
	 * Texte affichant le résultat de la consommation.
	 */
	private StringItem consommationSI;

	/**
	 * Commande pour lancer le calcul quand l'utilisateur le décide.
	 */
	private Command calculerCommand;

	/**
	 * Commande pour quitter la mobilette.
	 */
	private Command quitterCommand;

	/**
	 * Prévient la mobilette qu'elle va être affichée, soit pour la
	 * première fois, soit après après été mise en pause (pendant la réception
	 * d'un appel téléphonique par exemple).<br>
	 * Si c'est notre premier lancement (notre variable display est alors null)
	 * on initialise tout, y compris display qui du coup ne sera plus null
	 * si la même méthode est appelée après une pause. 
	 * @see javax.microedition.midlet.MIDlet#startApp()
	 */
	protected void startApp() throws MIDletStateChangeException
	{
		// Teste si on vient de démarrer (null)
		// ou si on est réveillé après une pause (non null)
		if (display == null)
		{ // on vient de démarrer => initialisations.
			display= Display.getDisplay(this); // récupère l'écran
			// construit un tableau qui contiendra tous les éléments de l'écran
			Item[] item= new Item[3];
			
			// Ajout des 2 zones de saisie
			kilometrageTF=
				new TextField("Kilométrage", "", 4, TextField.NUMERIC);
			// "Kilométrage" est le nom de la zone affiché à l'écran
			// "": la zone est initialement vide vide
			// 4 : est le nombre de caractère maximum saisissables dans la zone
			// TextField.NUMERIC : on ne peut saisir que des chiffres et
			//  éventuellement le signe '-' au début. Attention la zone peut
			//  être vide, ce qui n'est pas une valeur nuérique.
			item[0]= kilometrageTF;
			litresEssenceTF=
				new TextField("Litres d'essence", "", 3, TextField.NUMERIC);
			item[1]= litresEssenceTF;
			
			// Ajout de l'affichage du résultat
			consommationSI= new StringItem("Consommation (l/100km) ", "0");
			// Le premier paramètre est le titre. Il est suivi de ':' sur
			//  certains mobiles, sur d'autres il est en gras. On peut
			//  utiliser null si on n'a pas besoin de titre.
			// Le 2ème est le texte à afficher après le titre. On le mettra
			//  à jour plus tard avec la valeur calculée.
			item[2]= consommationSI;
			
			// Construit le formulaire
			formulaire= new Form("EcoLogic", item);
			
			// Nous voulons être prévenu quand il y a des saisies  
			formulaire.setItemStateListener(this);
			// Construction et ajout des commandes à l'écran
			calculerCommand= new Command("Calculer", Command.SCREEN, 1);
			// "Calculer" : Texte apparaissant dans le menu du téléphone.
			//   Ne mettez pas des textes longs (+ de 10 caractères) ils
			//   pourraient être tronqués.
			//  Command.SCREEN est le type de la commande. Le téléphone placera
			//   la commande à un endroit logique suivant son type et peut
			//   changer son texte, voir ne pas en mettre du tout. Ainsi
			//   Command.BACK peut être affecté à une touche spéciale du
			//   téléphone, mais ne pas apparaître à l'écran. Donner
			//   un bon type vous garantira une ergonomie correcte sur tous les
			//   modèles. Tricher améliorera l'usage sur 2-3 modèles et rendra
			//   l'application non ergonomique sur des dizaines d'autres!
			//   Ici avec Command.SCREEN on informe que la commande est relative
			//   aux informations affichées à l'écran. Lisez la doc de la
			//   classe Command pour connaître tous les types.
			// 1: c'est la priorité de la commande, 1 étant la plus importante.
			//  Une autre commande de même type et de priorité 2 sera placée
			//  en dessous dans les menus. Notez que les commandes peuvent
			//  être classées par type, puis par priorité sur certains modèles
			//  alors que d'autres calsseront seulement par priorité.
			formulaire.addCommand(calculerCommand);
			quitterCommand= new Command("Quitter", Command.EXIT, 2);
			formulaire.addCommand(quitterCommand);
			
			// Nous voulons être prévenu quand une commande est utilisée
			formulaire.setCommandListener(this);
			// Affiche le formulaire maintenant qu'il est configuré
			display.setCurrent(formulaire);
		}
	}

	/**
	 * Met la mobilette en pause. Dans notre cas on ne fait pas de traitement
	 * dans des threads en tâche de fond, donc cette méthode est vide.
	 * @see javax.microedition.midlet.MIDlet#pauseApp()
	 */
	protected void pauseApp()
	{
	}

	/**
	 * Indique à la mobilette qu'elle va être arrêtée et qu'elle doit tout
	 * de suite libérer ses ressources (connexions réseau, fermer ses flux
	 * vers la mémoire flash,...). Ici on n'utilise aucune ressource qui
	 * doive être fermée donc on ne fait rien.
	 * @see javax.microedition.midlet.MIDlet#destroyApp(boolean)
	 */
	protected void destroyApp(boolean arg0) throws MIDletStateChangeException
	{
	}

	/**
	 * Appelée quand un des TextField est mis à jour par l'utilisateur,
	 * on met alors à jour la consommation affichée.<br>
	 * C'est une méthode de l'interface ItemStateListener que nous implémentons.
	 * @param item Item dont le contenu a changé.
	 * @see javax.microedition.lcdui.ItemStateListener
	 */
	public void itemStateChanged(Item item)
	{
		// on ne tient pas compte de l'item à l'origine du changement,
		// on raffraîchit dans tous les cas.
		calculeConso();
	}

	/**
	 * Calcule la consommation à partir des 2 zones de saisie et met à jour
	 * le résultat à l'écran.
	 * @return String La consommation si le calcul a bien eu lieu, ou
	 * 	<code>null</code> en cas de problème (pas de saisie, division par 0).
	 */
	private String calculeConso()
	{
		String conso;
		String resultat;
		try
		{
			int km, litres;
			km= Integer.parseInt(kilometrageTF.getString());
			litres= Integer.parseInt(litresEssenceTF.getString());
			// on utilise la valeur absolue, évite pb si saisie d'un négatif
			// on arrondit en multipliant par 10, ajoutant 5 et divisant par 10.
			int consoEnDeciLitres= Math.abs((10000 * litres / km + 5) / 10);
			int consoEntiere= consoEnDeciLitres / 10;
			// construit la chaîne de caractère avec le nombre à virgule
			conso= consoEntiere + "," + (consoEnDeciLitres - consoEntiere * 10);
			// Relarquez qu'on a pas de float en CLDC 1.0 mais qu'on peut
			// se débrouiller sans et affciher des nombres à virgule.
			resultat= conso;
		}
		catch (Exception e)
		{ // En cas d'erreur (valeur non remplie, division par 0...)
			// on affiche une consommation de 0;
			conso= "0";
			resultat= null;
		}
		// on met à jour le texte.
		consommationSI.setText(conso);
		
		return resultat;
	}

	/**
	 * Appelée quand l'utilisateur choisit une commande affichée à l'écran.
	 * @param commande Command choisie par l'utilisateur.
	 * @param ecran Displayable sur lequel la commande était présente. Dans
	 *		cette application nous n'en avons pas besoin (un seul écran). 
	 * @see javax.microedition.lcdui.CommandListener
	 */
	public void commandAction(Command commande, Displayable ecran)
	{
		if (commande == quitterCommand)
		{
			notifyDestroyed(); // on signale au système qu'on a fini
		}
		else if (commande == calculerCommand)
		{ // on affiche une fenêtre d'information avec le résultat
			// ou un message d'erreur si le calcul est impossible.
			String conso= calculeConso();
			String titre, texte;
			AlertType type;
			if (conso != null)
			{
				titre= "Résultat";
				texte= "Vous avez consommé " + conso + "l/100km";
				type= AlertType.INFO;
				// la fenêtre ser une fenêtre d'information. Certaines marques
				// ajoutent un bip spécial et une icône (un i vert par exemple)
				// D'autres marques ne tiennent pas compte du type, toutes
				// les fenêtres d'Alert ayant le même aspect.
			}
			else
			{
				titre= "Erreur";
				texte=
					"Calcul impossible! Saisissez un kilométrage non nul "
						+ "et une quantité d'essence.";
				type= AlertType.ERROR;
			}
			Alert alert= new Alert(titre, texte, null, type);
			// on veut que la fenêtre reste affichée jusqu'à ce que
			// l'utilisateur valide le message
			alert.setTimeout(Alert.FOREVER);
			// On demande l'affichage de l'alerte en indiquant quel écran
			// sera affiché ensuite (ici notre formulaire de saisie) 
			display.setCurrent(alert, formulaire);
		}
	}
}

