package com.skatestown.invoice;
import java.io.InputStream;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParsersFactory;
import org.xml.sax.helpers.DefaultHandler;

/***
 * Sprawdzenie faktury firmy SkatesTown z wykorzystaniem parsera SAX.
 */
public class InvoiceCheckerSAX
extends DefaultHandler
implements InvoiceChecker
{
// zmiene na poziomie klasy
// aktualna suma kosztw 
double runningTotal = 0.0;
// suma kosztw
double total = 0.0;

// zmienne pomocnicze do odczytywania kwot z tekstu
boolean isMoneyContent = false;
double amount = 0.0;

/**
 * Sprawdza poprawno sumarycznej kwoty.
 * @param	invoiceXML	faktura w formacie XML
 * @exception	Exception	dowolny wyjtek, jaki moe zosta zgoszony w czasie wykonania funkcji
 */
public void checkInvoice (InputStream invoiceXML) throws Exception {
// uywamy domylnego parsera (niewalidujcego)
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
// parsujemy strumie wejciowy; ten obiekt obsuguje zdarzenia SAX
saxParser.parse(invoiceXML, this);
	}

// metody interfejsu DocumentHandler
public void startDocument() throws SAXException {
runningTotal = 0.0;
total = 0.0;
isMoneyContent = false;
	}

public void endDocument() throws SAXException {
		// Przy sprawdzaniu rwnoci dopuszczamy pewien bd, aby obsuy ewentualne
		// skumulowanie bdw arytmetyki zmiennopozycyjnej. Dopuszczalnym bdem jest 0.005.
		if (Math.abs(runningTotal - total) >= 0.005) {
			throw new SAXException (
				"Bd na fakturze: suma wynosi " + Double.toString(total) + 
				"a obliczona warto to " + Double.toString(Math.round(runningTotal * 100) / 100.0));
		}
	}

public void startElement(String namespaceURI, String localName, String qualifiedName, Attributes attrs) throws SAXException {
if (localName.equals("item")) {
// obliczamy warto pozycji zamwienia i dodajemy j do aktualnej sumy
runningTotal += Integer.valueOf(attrs.getValue(namespaceURI, "quantity")).intValue() * Double.valueOf(attrs.getValue(namespaceURI, "unitPrice")).doubleValue();
} else if (localName.equals("tax") || localName.equals("shippingAndHandling") || localName.equals("totalCost")) {
// przygotowujemy si do odczytania kwoty
isMoneyContent = true;
		}
	}

public void endElement(String namespaceURI, String localName, String qualifiedName) throws SAXException {
if (isMoneyContent) {
if (localName.equals("totalCost")) {
total = amount;
} else {
// musi to by tax albo shippingAndHandling
runningTotal += amount;
			}
isMoneyContent = false;
		}
	}

public void characters(char buf[], int offset, int len) throws SAXException {
if (isMoneyContent) {
String value = new String(buf, offset, len);
amount = Double.valueOf(value).doubleValue();
		}
	}
}
