/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package de.christofreichardt.jaxws.securitypriceservice;

import de.christofreichardt.diagnosis.AbstractTracer;
import de.christofreichardt.diagnosis.LogLevel;
import de.christofreichardt.diagnosis.Traceable;
import de.christofreichardt.diagnosis.TracerFactory;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 *
 * @author Christof Reichardt
 */
public class OnVistaExtractor implements PriceExtractorStrategy, Traceable {

    @Override
    public AbstractSecurityPrice extractPrice(String id) throws SecurityPriceServiceException {
        AbstractTracer tracer = getCurrentTracer();
        tracer.entry("AbstractSecurityPrice", this, "extractPrice(String id)");

        try {
            tracer.out().printfIndentln("id = %s", id);

            AbstractSecurityPrice securityPrice;
            try {
                Document document = Jsoup.connect("http://www.onvista.de/suche/" + id).timeout(25000).userAgent("Mozilla").get();
                SecurityType securityType = determineType(document);
                switch (securityType) {
                    case SHARE:
                        securityPrice = evaluateShare(document);
                        break;
                    case OPTION:
                        securityPrice = evaluateOption(document);
                        break;
                    case INDEX_CERTIFICATE:
                        securityPrice = evaluateIndex(document);
                        break;
                    default:
                        securityPrice = handleUnknownSecurity(id);
                        break;
                }

                return securityPrice;
            } catch (IOException ex) {
                tracer.logException(LogLevel.ERROR, ex, getClass(), "extractPrice(String id)");
                throw makeFault(ex.getMessage());
            }
        } finally {
            tracer.wayout();
        }
    }

    private SecurityType determineType(Document document) {
        AbstractTracer tracer = getCurrentTracer();
        tracer.entry("SecurityType", this, "determineType(Document document)");

        try {
            SecurityType securityType = SecurityType.UNKNOWN;

            if (securityType == SecurityType.UNKNOWN) {
                Element term = document.select("div#ONVISTA div.WEBSEITE div.CONTAINER1 div.INHALT article div.WERTPAPIER span.WERTPAPIERNAME a.INSTRUMENT span.INSTRUMENT.AKTIE").first();
                if (term != null && "Aktie".equals(term.text())) {
                    securityType = SecurityType.SHARE;
                }
            }

            if (securityType == SecurityType.UNKNOWN) {
                Element category = document.select("div#ONVISTA main#snapshot section.main-content section.content-section table#table-indicators-second tbody tr td").first();
                if (category != null && category.text().startsWith("Optionsscheine")) {
                    securityType = SecurityType.OPTION;
                }
            }

            if (securityType == SecurityType.UNKNOWN) {
                Element category = document.select("div#ONVISTA main#snapshot section.main-content section.content-section table#table-indicators-second tbody tr td").first();

                if (category != null) {
                    tracer.out().printfIndentln("category.text() = %s", category.text());
                } else {
                    tracer.out().printfIndentln("category is null.");
                }

                if (category != null && category.text().startsWith("Index- und Partizipations-Zertifikate")) {
                    securityType = SecurityType.INDEX_CERTIFICATE;
                }
            }

            return securityType;
        } finally {
            tracer.wayout();
        }
    }

    private UnknownPrice handleUnknownSecurity(String id) {
        AbstractTracer tracer = getCurrentTracer();
        tracer.entry("UnknownPrice", this, "handleUnknownSecurity(String id)");

        try {
            ObjectFactory objectFactory = new ObjectFactory();
            Security security = objectFactory.createSecurity();
            if (id.length() == 6) {
                security.setWKN(id);
            } else if (id.length() == 12) {
                security.setISIN(id);
            }
            UnknownPrice unknownPrice = objectFactory.createUnknownPrice();
//      UnknownPrice unknownPrice = new MyUnknownPrice();
            unknownPrice.setSecurity(security);

            return unknownPrice;
        } finally {
            tracer.wayout();
        }
    }

    private SharePrice evaluateShare(Document document) throws SecurityPriceServiceException {
        AbstractTracer tracer = getCurrentTracer();
        tracer.entry("SharePrice", this, "evaluateShare(Document document)");

        try {
            ObjectFactory objectFactory = new ObjectFactory();
            Security security = objectFactory.createSecurity();
            SharePrice sharePrice = objectFactory.createSharePrice();
            sharePrice.setSecurity(security);

            Elements elements = document.select("div#ONVISTA div.WEBSEITE div.CONTAINER1 div.INHALT article div.WERTPAPIER_DETAILS dl dd");
            if (elements.size() != 6) {
                throw makeFault("Unexpected page layout.");
            }
            Element wkn = elements.first();
            Element isin = elements.get(1);
            Element anchor = document.select("div#ONVISTA div.WEBSEITE div.CONTAINER1 div.INHALT article div.WERTPAPIER span.WERTPAPIERNAME a.INSTRUMENT").first();
            if (anchor == null) {
                throw makeFault("Unexpected page layout.");
            }
            Element rate = document.select("div#ONVISTA div.WEBSEITE div.CONTAINER1 div.INHALT article ul.KURSDATEN li span").first();
            if (rate == null) {
                throw makeFault("Unexpected page layout.");
            }

            tracer.out().printfIndentln("wkn.text() = %s", wkn.text());
            tracer.out().printfIndentln("isin.text() = %s", isin.text());
            tracer.out().printfIndentln("anchor.text() = %s", anchor.text());
            tracer.out().printfIndentln("rate.text() = %s", rate.text());

            security.setISIN(isin.text());
            security.setWKN(wkn.text().substring(0, 6));
            security.setName(anchor.text());
            sharePrice.setRate(new BigDecimal(rate.text().replace(".", "").replace(",", ".")));

            return sharePrice;
        } finally {
            tracer.wayout();
        }
    }

    private OptionPrice evaluateOption(Document document) throws SecurityPriceServiceException {
        AbstractTracer tracer = getCurrentTracer();
        tracer.entry("OptionPrice", this, "evaluateOption(Document document)");

        try {
            ObjectFactory objectFactory = new ObjectFactory();
            Security security = objectFactory.createSecurity();
            OptionPrice optionPrice = objectFactory.createOptionPrice();
            optionPrice.setSecurity(security);

            Element h1 = document.select("div#ONVISTA main#snapshot header.main-header div.headline h1.inline").first();
            if (h1 == null) {
                throw makeFault("Unexpected page layout.");
            }
            String securityName = h1.text();

            tracer.out().printfIndentln("securityName = %s", securityName);

            Elements spans = document.select("div#ONVISTA main#snapshot header.main-header small span");
            if (spans.size() < 2) {
                throw makeFault("Unexpected page layout.");
            }

            String wkn = spans.get(0).text();
            if (wkn.startsWith("WKN: ") && wkn.length() > 5) {
                wkn = wkn.substring(5);
            } else {
                throw makeFault("Unexpected page layout.");
            }
            String isin = spans.get(1).text();
            if (isin.startsWith("ISIN: ") && isin.length() > 6) {
                isin = isin.substring(6);
            } else {
                throw makeFault("Unexpected page layout.");
            }

            tracer.out().printfIndentln("wkn = %s", wkn);
            tracer.out().printfIndentln("isin = %s", isin);

            Elements tds = document.select("div#ONVISTA main#snapshot section.main-content section.content-section table#table-indicators-second tbody tr td");

            if (tds.size() < 9) {
                throw makeFault("Unexpected page layout.");
            }
            String strikePrice = tds.get(1).text();
            String exercise = tds.get(8).text();

            tracer.out().printfIndentln("tds.size() = %d", tds.size());
            tracer.out().printfIndentln("strikePrice = %s", strikePrice);
            tracer.out().printfIndentln("exercise = %s", exercise);

            Element span = document.select("div#ONVISTA main#snapshot header.main-header div.row div.col-4.bid-price div.header-quote ul li.quote span.price").first();
            if (span == null) {
                throw makeFault("Unexpected page layout.");
            }
            String bid = span.text();
            if (bid.endsWith(" EUR")) {
                bid = bid.substring(0, bid.length() - 4);
            } else {
                throw makeFault("Unexpected page layout.");
            }
            
            tracer.out().printfIndentln("bid = %s", bid);

            span = document.select("div#ONVISTA main#snapshot header.main-header div.row div.col-4.ask-price div.header-quote ul li.quote span.price").first();
            if (span == null) {
                throw makeFault("Unexpected page layout.");
            }
            String ask = span.text();
            if (ask.endsWith(" EUR")) {
                ask = ask.substring(0, ask.length() - 4);
            } else {
                throw makeFault("Unexpected page layout.");
            }
            
            tracer.out().printfIndentln("ask = %s", ask);

//            tracer.out().printfIndentln("expirationDate = %s", expirationDate);
//            tracer.out().printfIndentln("StringUtil.trim(expirationDate) = %s", StringUtil.trim(expirationDate));

            security.setISIN(isin);
            security.setWKN(wkn);
            security.setName(securityName);
            optionPrice.setExercise("Amerikanisch".equalsIgnoreCase(exercise) ? Exercise.AMERICAN : Exercise.EUROPEAN);
            optionPrice.setStrikePrice(new BigDecimal(strikePrice.replace(".", "").replace(",", ".")));
            if (!"n.a.".equals(bid)) {
                optionPrice.setBid(new BigDecimal(bid.replace(".", "").replace(",", ".")));
            }
            if (!"n.a.".equals(ask)) {
                optionPrice.setAsk(new BigDecimal(ask.replace(".", "").replace(",", ".")));
            }
            
//            Scanner scanner = new Scanner(StringUtil.trim(expirationDate));
//            scanner.useDelimiter("\\.");
//            try {
//                int day = scanner.nextInt();
//                int month = scanner.nextInt();
//                String year = scanner.next();
//                XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory.newInstance().
//                    newXMLGregorianCalendar(new BigInteger(year), month, day, 0, 0, 0, new BigDecimal(0), 0);
//                optionPrice.setExpirationDate(xmlGregorianCalendar);
//
//                tracer.out().printfIndentln("xmlGregorianCalendarDate = %s", xmlGregorianCalendar);
//            } catch (DatatypeConfigurationException ex) {
//                throw makeFault(ex.getMessage());
//            }

            return optionPrice;
        } finally {
            tracer.wayout();
        }
    }

    private IndexPrice evaluateIndex(Document document) throws SecurityPriceServiceException {
        AbstractTracer tracer = getCurrentTracer();
        tracer.entry("IndexPrice", this, "evaluateIndex(Document document)");

        try {
            ObjectFactory objectFactory = new ObjectFactory();
            Security security = objectFactory.createSecurity();
            IndexPrice indexPrice = objectFactory.createIndexPrice();
            indexPrice.setSecurity(security);

            Element td = document.select("div#ONVISTA main#snapshot header.main-header div.row div.col-4 div.header-quote ul li.quote span.price").first();
            if (td == null) {
                throw makeFault("Unexpected page layout.");
            }
            Element span = td.select("span").last();
            if (span == null) {
                throw makeFault("Unexpected page layout.");
            }
            String bid = span.text();
            if (bid.endsWith(" EUR")) {
                bid = bid.substring(0, bid.length() - 4);
            } else {
                throw makeFault("Unexpected page layout.");
            }

            tracer.out().printfIndentln("bid = %s", bid);

            td = document.select("div#ONVISTA main#snapshot header.main-header div.row div.col-4.ask-price div.header-quote ul li.quote span.price").last();
            if (td == null) {
                throw makeFault("Unexpected page layout.");
            }
            span = td.select("span").last();
            if (span == null) {
                throw makeFault("Unexpected page layout.");
            }
            String ask = td.select("span").last().text();
            if (ask.endsWith(" EUR")) {
                ask = ask.substring(0, ask.length() - 4);
            } else {
                throw makeFault("Unexpected page layout.");
            }

            tracer.out().printfIndentln("ask = %s", ask);

            Element img = document.select("div#ONVISTA main#snapshot header.main-header small a.blue img").first();
            if (img == null) {
                throw makeFault("Unexpected page layout.");
            }
            String issuer = img.attr("title");

            tracer.out().printfIndentln("issuer = %s", issuer);

            Element h1 = document.select("div#ONVISTA main#snapshot header.main-header div.headline h1.inline.name").first();
            if (h1 == null) {
                throw makeFault("Unexpected page layout.");
            }
            String name = h1.text();

            tracer.out().printfIndentln("name = %s", name);

            Elements spans = document.select("div#ONVISTA main#snapshot header.main-header small span");
            if (spans.size() < 2) {
                throw makeFault("Unexpected page layout.");
            }

            String wkn = spans.get(0).text();
            if (wkn.startsWith("WKN: ") && wkn.length() > 5) {
                wkn = wkn.substring(5);
            } else {
                throw makeFault("Unexpected page layout.");
            }
            String isin = spans.get(1).text();
            if (isin.startsWith("ISIN: ") && isin.length() > 6) {
                isin = isin.substring(6);
            } else {
                throw makeFault("Unexpected page layout.");
            }

            tracer.out().printfIndentln("wkn = %s", wkn);
            tracer.out().printfIndentln("isin = %s", isin);

            security.setName(name);
            security.setWKN(wkn);
            security.setISIN(isin);
            if (!"n.a.".equals(bid)) {
                indexPrice.setBid(new BigDecimal(bid.replace(".", "").replace(",", ".")));
            }
            if (!"n.a.".equals(ask)) {
                indexPrice.setAsk(new BigDecimal(ask.replace(".", "").replace(",", ".")));
            }
            indexPrice.setIssuer(issuer);

            return indexPrice;
        } finally {
            tracer.wayout();
        }
    }

//  private void checkPageLayout(Element element) throws SecurityPriceServiceException {
//    AbstractTracer tracer = getCurrentTracer();
//    tracer.entry("void", this, "checkPageLayout(Element element)");
//    
//    try {
//      if (element == null) {
//        SecurityPriceServiceFault securityPriceServiceFault = new SecurityPriceServiceFault();
//        securityPriceServiceFault.setMessage("Unexpected page layout.");
//        throw new SecurityPriceServiceException(securityPriceServiceFault);
//      }
//    }
//    finally {
//      tracer.wayout();
//    }
//  }
    private SecurityPriceServiceException makeFault(String message) {
        AbstractTracer tracer = getCurrentTracer();
        tracer.entry("void", this, "throwFault(String message)");

        try {
            SecurityPriceServiceFault securityPriceServiceFault = new SecurityPriceServiceFault();
            securityPriceServiceFault.setMessage(message);
            return new MySecurityPriceServiceException(securityPriceServiceFault);
        } finally {
            tracer.wayout();
        }
    }

    @Override
    public AbstractTracer getCurrentTracer() {
        return TracerFactory.getInstance().getCurrentQueueTracer();
    }

}
