/**********************************************************************
 *
 * This file is part of HBCI4Java.
 * Copyright (c) 2001-2008 Stefan Palme
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **********************************************************************/

package org.kapott.hbci.GV;

import java.text.SimpleDateFormat;
import java.util.Properties;

import org.kapott.hbci.GV_Result.GVRWPDepotUms;
import org.kapott.hbci.GV_Result.GVRWPDepotUms.Entry.FinancialInstrument;
import org.kapott.hbci.GV_Result.GVRWPDepotUms.Entry.FinancialInstrument.Transaction;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.manager.HBCIHandler;
import org.kapott.hbci.manager.LogFilter;
import org.kapott.hbci.passport.HBCIPassport;
import org.kapott.hbci.status.HBCIMsgStatus;
import org.kapott.hbci.structures.BigDecimalValue;
import org.kapott.hbci.structures.Konto;
import org.kapott.hbci.structures.TypedValue;
import org.kapott.hbci.swift.Swift;

public class GVWPDepotUms 
extends HBCIJobImpl
{
    private StringBuffer buffer;

    public static String getLowlevelName()
    {
        return "WPDepotUms";
    }

    public GVWPDepotUms(HBCIHandler handler)
    {
        super(handler,getLowlevelName(),new GVRWPDepotUms());
        this.buffer=new StringBuffer();

        HBCIPassport passport=handler.getPassport();

        addConstraint("my.number","Depot.number",null, LogFilter.FILTER_IDS);
        addConstraint("my.subnumber","Depot.subnumber","", LogFilter.FILTER_MOST);

        addConstraint("my.country","Depot.KIK.country",passport.getUPD().getProperty("KInfo.KTV.KIK.country"), LogFilter.FILTER_NONE);
        addConstraint("my.blz","Depot.KIK.blz",passport.getUPD().getProperty("KInfo.KTV.KIK.blz"), LogFilter.FILTER_MOST);
        //addConstraint("my.curr","curr",passport.getUPD().getProperty("KInfo.cur",""), LogFilter.FILTER_NONE);
        addConstraint("quality","quality","", LogFilter.FILTER_NONE);
        addConstraint("maxentries","maxentries","", LogFilter.FILTER_NONE);
        
        addConstraint("startdate","startdate","", LogFilter.FILTER_NONE);
        addConstraint("enddate","enddate","", LogFilter.FILTER_NONE);
        
        addConstraint("dummy","alldepots","N", LogFilter.FILTER_NONE);
    }

    private TypedValue parseTypedValue(String st) {
        String st_type=st.substring(7,11);
        String curr="";
        boolean withCurr = false;

        int saldo_type = -1;
        if (st_type.equals("FAMT")) { 
            saldo_type=TypedValue.TYPE_WERT;
        } else if (st_type.equals("ACTU")) { 
            saldo_type=TypedValue.TYPE_WERT;
            withCurr = true;
        } else if (st_type.equals("UNIT")) {
            saldo_type=TypedValue.TYPE_STCK;
        } else if (st_type.equals("PRCT")) {
            saldo_type=TypedValue.TYPE_PROZENT;
        }
        int pos1=12;
        boolean neg = (st.charAt(pos1)=='N');
        if (neg)
            pos1++;    
        if (withCurr) {
            curr = st.substring(pos1, pos1+3);
            pos1 += 3;
        } 
        return new TypedValue(
                            (neg?"-":"")+st.substring(pos1).replace(',','.'),
                            curr,
                            saldo_type);
    }

    /**
     * @see org.kapott.hbci.GV.HBCIJobImpl#redoAllowed()
     */
    @Override
    protected boolean redoAllowed()
    {
        return true;
    }

    protected void extractResults(HBCIMsgStatus msgstatus,String header,int idx) 
    {
        Properties result=msgstatus.getData();

        buffer.append(Swift.decodeUmlauts(result.getProperty(header + ".data536")));

        final SimpleDateFormat date_time_format = new SimpleDateFormat("yyyyMMdd hhmmss");
        final SimpleDateFormat date_only_format = new SimpleDateFormat("yyyyMMdd");

        while (buffer.length()!=0) {
            try {
                String onerecord=Swift.getOneBlock(buffer);

                GVRWPDepotUms.Entry entry=new GVRWPDepotUms.Entry();

                String st_timestamp=null;
                String st_date=null;
                String st_time=null;
                char option='C';
                int  i=0;

                while (true) {
                    //Parse allgemeine Informationen (Mandatory Sequence A General Information)
                    st_timestamp=Swift.getTagValue(onerecord,"98"+option,i++);
                    if (st_timestamp==null) {
                        if (option=='C') {
                            option='A';
                            i=0;
                        } else {
                            break;
                        }
                    } else {
                        if (st_timestamp.substring(1,5).equals("PREP")) {
                            st_date=st_timestamp.substring(7,15);
                            if (option=='C') {
                                st_time=st_timestamp.substring(15,21);
                            }
                            break;
                        }
                    }
                } 


                if (st_time!=null) {
                    entry.timestamp=date_time_format.parse(st_date+" "+st_time);
                } else if (st_date != null) {
                    entry.timestamp=date_only_format.parse(st_date);
                }

                String st_depot=Swift.getTagValue(onerecord,"97A",0);
                int pos1=st_depot.indexOf("//");
                int pos2=st_depot.indexOf("/",pos1+2);
                if (pos2<0)
                    pos2=st_depot.length();
                entry.depot=new Konto();
                entry.depot.blz=st_depot.substring(pos1+2,pos2);
                if (pos2 < st_depot.length())
                    entry.depot.number=st_depot.substring(pos2+1);
                getMainPassport().fillAccountInfo(entry.depot);

                String st;
                i=0;
                // Parse einzelnes Finanzinstrument (Repetitive Optional Subsequence B1 Financial Instrument)
                st=Swift.getTagValue(onerecord,"17B",0);
                if (st.substring(st.indexOf("//")+2).equals("Y")) {
                    int fin_start=onerecord.indexOf(":16R:FIN");

                    while (true) {
                        int fin_end=onerecord.indexOf(":16S:FIN",fin_start);
                        if ((fin_end)==-1) {
                            break;
                        }

                        String oneinstrument=onerecord.substring(fin_start,fin_end+8);
                        fin_start+=oneinstrument.length();

                        FinancialInstrument instrument=new GVRWPDepotUms.Entry.FinancialInstrument();

                        int trans_start = oneinstrument.indexOf(":16R:TRAN\r\n");
                        String oneinstrument_header;
                        if (trans_start >= 0)
                            oneinstrument_header = oneinstrument.substring(0, trans_start+9);
                        else
                            oneinstrument_header = oneinstrument;
                        
                        st=Swift.getTagValue(oneinstrument_header,"35B",0);
                        boolean haveISIN=st.substring(0,5).equals("ISIN ");

                        if (haveISIN) {
                            pos1=st.indexOf("\r\n");
                            instrument.isin=st.substring(5,pos1);
                            if (pos1+2<st.length() && st.substring(pos1+2,pos1+6).equals("/DE/")) {
                                pos2=st.indexOf("\r\n",pos1+6);
                                if (pos2==-1) {
                                    pos2=st.length();
                                }
                                instrument.wkn=st.substring(pos1+6,pos2);
                                pos1=pos2;
                            }
                        } else {
                            pos1=st.indexOf("\r\n");
                            instrument.wkn=st.substring(4,pos1);
                        }

                        pos1+=2;
                        if (pos1<st.length())
                            instrument.name=st.substring(pos1);

                        if (instrument.name!=null) {
                            StringBuffer sb=new StringBuffer(instrument.name);
                            int p;
                            while ((p=sb.indexOf("\r\n"))!=-1) {
                                sb.replace(p,p+2," ");
                            }
                            instrument.name=sb.toString();
                        }
                        i=0;
                        while (true) {
                            st=Swift.getTagValue(oneinstrument_header,"93B",i++);
                            if (st==null)
                                break;
                            String qualifier = st.substring(1,5);

                            if ("FIOP".equals(qualifier) || (instrument.startSaldo == null && "INOP".equals(qualifier))) {
                                instrument.startSaldo = parseTypedValue(st);
                            } else if ("FICL".equals(qualifier) || (instrument.endSaldo == null && "INCL".equals(qualifier))) {
                                instrument.endSaldo   = parseTypedValue(st);
                            } else {
                                System.out.println("Unbekannter 93B: " + st);
                            }
                        }
                        
                        i=0;
                        while (true) {
                            st=Swift.getTagValue(oneinstrument_header,"98A",i++);
                            if (st==null)
                                break;
                            String qualifier = st.substring(1,5);

                            if ("PRIC".equals(qualifier)) {
                                instrument.preisdatum = date_only_format.parse(st.substring(7, 15));
                            } else {
                                System.out.println("Unbekannter 98A: " + st);
                            }
                        }

                        i=0;
                        while (true) {
                            st=Swift.getTagValue(oneinstrument_header,"90A",i++);
                            if (st==null)
                                break;
                            
                            instrument.preis = parseTypedValue(st);
                        }
                        
                        i=0;
                        while (true) {
                            st=Swift.getTagValue(oneinstrument_header,"90B",i++);
                            if (st==null)
                                break;
                            
                            instrument.preis = parseTypedValue(st);
                        }
                        
                        //Parse einzelne Transaktionen 
                        while (trans_start >= 0) {
                            int trans_end = oneinstrument.indexOf(":16S:TRAN\r\n", trans_start);
                            if (trans_end<0)
                                break;
                            String onetransaction = oneinstrument.substring(trans_start, trans_end+9);
                            trans_start=trans_end+9;

                            Transaction transaction = new Transaction();

                            int link_start = onetransaction.indexOf(":16R:LINK");
                            if (link_start >=0) {
                                int link_end = onetransaction.indexOf(":16S:LINK", link_start);
                                if (link_end >= 0) {
                                    String onelink = onetransaction.substring(link_start, link_end+8);
                                    String rela = Swift.getTagValue(onelink, "20C", 0);

                                    if (rela != null) {
                                        transaction.kundenreferenz = rela.substring(7);
                                    }
                                }
                            }

                            int detail_start = onetransaction.indexOf(":16R:TRANSDET");
                            if (detail_start >= 0) {
                                int detail_end = onetransaction.indexOf(":16S:TRANSDET", detail_start);
                                if (detail_end >= 0) {
                                    String onedetail = onetransaction.substring(detail_start, detail_end+12);

                                    String quantity = Swift.getTagValue(onedetail, "36B", 0);
                                    if (quantity != null)
                                        if (quantity.startsWith(":PSTA")) {
                                            transaction.anzahl = parseTypedValue(quantity);
                                        } else {
                                            System.out.println("Unbekannter 36B: " + quantity);
                                        }
                                    
                                    String t99a = Swift.getTagValue(onedetail, "99A", 0);
                                    if (t99a != null)
                                        if (t99a.startsWith(":DAAC")) {
                                            int neg = 0;
                                            if (t99a.charAt(7) == 'N')
                                                neg = 1;
                                            transaction.stueckzins_tage = Integer.parseInt(t99a.substring(7+neg));
                                            if (neg != 0)
                                                transaction.stueckzins_tage = -transaction.stueckzins_tage;
                                        } else {
                                            System.out.println("Unbekannter 99A: " + t99a);
                                        }
                                    
                                    int tagidx = 0;
                                    while (true) {
                                        String t19a = Swift.getTagValue(onedetail, "19A", tagidx++);
                                        if (t19a == null)
                                            break;

                                        if (t19a.startsWith(":PSTA")) {
                                            int off=7;
                                            if (t19a.charAt(off)=='N') 
                                                off++;
                                            transaction.betrag=new BigDecimalValue(
                                                            t19a.substring(off+3).replace(',','.'),
                                                            t19a.substring(off,off+3));
                                            if (off>7)
                                                transaction.betrag.setValue(transaction.betrag.getValue().negate());
                                        } else if (t19a.startsWith(":ACRU")) {
                                            int off=7;
                                            if (t19a.charAt(off)=='N') 
                                                off++;
                                            transaction.stueckzinsen=new BigDecimalValue(
                                                            t19a.substring(off+3).replace(',','.'),
                                                            t19a.substring(off,off+3));
                                            if (off>7)
                                                transaction.stueckzinsen.setValue(transaction.stueckzinsen.getValue().negate());
                                        } else {
                                            System.out.println("Unbekannter 19A: " + t19a);
                                        }
                                    }

                                    tagidx=0;
                                    while (true) {
                                        String t22f = Swift.getTagValue(onedetail, "22F", tagidx++);
                                        if (t22f == null)
                                            break;

                                        if (t22f.startsWith(":TRAN")) {
                                            if (t22f.endsWith("SETT")) {
                                                transaction.transaction_indicator = Transaction.INDICATOR_SETTLEMENT_CLEARING;
                                            } else if (t22f.endsWith("CORP")) {
                                                transaction.transaction_indicator = Transaction.INDICATOR_CORPORATE_ACTION;
                                            } else if (t22f.endsWith("BOLE")) {
                                                transaction.transaction_indicator = Transaction.INDICATOR_LEIHE;
                                            } else if (t22f.endsWith("COLL")) {
                                                transaction.transaction_indicator = Transaction.INDICATOR_SICHERHEITEN;
                                            } else {
                                                System.out.println("Unbekannter 22F->TRAN: " + t22f);
                                                transaction.transaction_indicator = -1;
                                            }
                                        } else if (t22f.startsWith(":CCPT")) {
                                            if (t22f.endsWith("YCCP")) {
                                                transaction.ccp_eligibility = true;
                                            } else {
                                                System.out.println("Unbekannter 22F->CCPT: " + t22f);
                                            }
                                        } else {
                                            System.out.println("Unbekannter 22F: " + t22f);
                                        }
                                    }

                                    tagidx=0;
                                    while (true) {
                                        String t22h = Swift.getTagValue(onedetail, "22H", tagidx++);
                                        if (t22h == null)
                                            break;

                                        if (t22h.startsWith(":REDE")) {
                                            if (t22h.endsWith("DELI")) {
                                                transaction.richtung = Transaction.RICHTUNG_LIEFERUNG;
                                            } else if (t22h.endsWith("RECE")) {
                                                transaction.richtung = Transaction.RICHTUNG_ERHALT;
                                            } else {
                                                System.out.println("Unbekannter 22H->REDE: " + t22h);
                                                transaction.richtung = -1;
                                            }
                                        } else if (t22h.startsWith(":PAYM")) {
                                            if (t22h.endsWith("APMT")) {
                                                transaction.bezahlung = Transaction.BEZAHLUNG_GEGEN_ZAHLUNG;
                                            } else if (t22h.endsWith("FREE")) {
                                                transaction.bezahlung = Transaction.BEZAHLUNG_FREI;
                                            } else {
                                                System.out.println("Unbekannter 22H->PAYM: " + t22h);
                                                transaction.bezahlung = -1;
                                            }
                                        } else {
                                            System.out.println("Unbekannter 22F: " + t22h);
                                        }
                                    }

                                    tagidx=0;
                                    while (true) {
                                        String t98a = Swift.getTagValue(onedetail, "98A", tagidx++);
                                        if (t98a == null)
                                            break;
                                        
                                        if (t98a.startsWith(":ESET")) {
                                            String datum = t98a.substring(7);
                                            transaction.datum = date_only_format.parse(datum);
                                        } else if (t98a.startsWith(":SETT")) {
                                            String datum = t98a.substring(7);
                                            transaction.datum_valuta = date_only_format.parse(datum);
                                        } else {
                                            System.out.println("Unbekannter 98A: " + t98a);
                                        }
                                    }
                                    
                                    String move = Swift.getTagValue(onedetail, "25D", 0);
                                    if (move != null) 
                                        if (move.startsWith(":MOVE")) {
                                            if (move.endsWith("REVE"))
                                                transaction.storno = true;
                                        } else  {
                                            System.out.println("Unbekannter 25D: " + move);
                                        }
                                    
                                    String freitext = Swift.getTagValue(onedetail, "70E", 0);
                                    if (freitext != null) 
                                        if (freitext.startsWith(":TRDE")) {
                                            transaction.freitext_details = freitext.substring(7);
                                        } else  {
                                            System.out.println("Unbekannter 70E: " + freitext);
                                        }
                                }
                            }

                            int party_start = onetransaction.indexOf(":16R:SETPRTY");
                            if (party_start >=0) {
                                int party_end = onetransaction.indexOf(":16S:SETPRTY", party_start);
                                if (party_end >= 0) {
                                    String oneparty = onetransaction.substring(party_start, party_end+10);
                                    String deag = Swift.getTagValue(oneparty, "95Q", 0);

                                    if (deag != null) {
                                        transaction.gegenpartei = deag.substring(7);
                                    }
                                }
                            }
                            
                            instrument.transactions.add(transaction);
                            trans_start = oneinstrument.indexOf(":16R:TRAN\r\n", trans_start);
                        }
                        entry.instruments.add(instrument);
                    }
                } 
                ((GVRWPDepotUms)jobResult).addEntry(entry);
                buffer.delete(0,onerecord.length());
            } catch (Exception e) {
                throw new HBCI_Exception("*** error while extracting data",e);
            }
        }

        ((GVRWPDepotUms)jobResult).rest=buffer.toString();                    
    }          

    public void verifyConstraints()
    {
        super.verifyConstraints();
        checkAccountCRC("my");
    }
}
