package uk.org.sappho.codeheatmap.ui.web.server.handlers;

import static ch.lambdaj.Lambda.by;
import static ch.lambdaj.Lambda.group;
import static ch.lambdaj.Lambda.on;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import net.customware.gwt.dispatch.server.ActionHandler;
import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.DispatchException;

import org.apache.log4j.Logger;

import uk.org.sappho.code.change.management.data.IssueData;
import uk.org.sappho.code.change.management.data.RawData;
import uk.org.sappho.code.change.management.data.persistence.ReaderRawDataPersistence;
import uk.org.sappho.codeheatmap.ui.web.shared.actions.DataItem;
import uk.org.sappho.codeheatmap.ui.web.shared.actions.FetchData;
import uk.org.sappho.codeheatmap.ui.web.shared.actions.FetchDataResult;
import ch.lambdaj.group.Group;

import com.google.inject.Inject;

public class FetchDataHandler implements ActionHandler<FetchData, FetchDataResult> {

    private static final Logger LOG = Logger.getLogger(FetchDataHandler.class);
    private final ReaderRawDataPersistence rawDataPersistence;

    @Inject
    public FetchDataHandler(ReaderRawDataPersistence rawDataPersistence) {
        this.rawDataPersistence = rawDataPersistence;
    }

    @Override
    public Class<FetchData> getActionType() {
        return FetchData.class;
    }

    @Override
    public FetchDataResult execute(FetchData action, ExecutionContext context)
            throws DispatchException {

        File dataFile = new File("WEB-INF/data/raw-data-all-frame-2010-12-14.zip");
        try {
            if (dataFile.exists()) {
                Reader reader = getDataFileReader(dataFile);
                RawData rawData = rawDataPersistence.load(reader);
                List<DataItem> data = massageData(rawData);
                return new FetchDataResult(data);
            } else {
                LOG.error("Couldn't find data file: " + dataFile.getCanonicalPath());
                return null;
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private List<DataItem> massageData(RawData rawData) {

        Collection<IssueData> issues = rawData.getIssueDataMap().values();
        Group<IssueData> releasesGroup = group(issues,
                by(on(IssueData.class).getMainRelease()),
                by(on(IssueData.class).getType()));
        ArrayList<String> releaseNames = new ArrayList<String>(releasesGroup.keySet());
        Collections.sort(releaseNames, new SortedAsIfNumbers());
        LOG.info("Found " + releaseNames.size() + " releases");

        List<DataItem> data = new ArrayList<DataItem>();
        for (String release : releaseNames) {
            Group<IssueData> releaseGroup = releasesGroup.findGroup(release);
            List<IssueData> changes = releaseGroup.find("change");
            List<IssueData> defects = releaseGroup.find("defect");
            if (release != null && !release.isEmpty()) {
                data.add(new DataItem(release, changes.size(), defects.size()));
            }
        }
        return data;
    }

    private Reader getDataFileReader(File dataFile) throws IOException, ZipException {
        LOG.info("Fetching data from: " + dataFile.getCanonicalFile());
        ZipFile zipFile = new ZipFile(dataFile);
        LOG.info("Found " + zipFile.size() + " entries in zip file");
        LOG.info("First file: " + zipFile.entries().nextElement().getName());
        String entryName = zipFile.entries().nextElement().getName();
        ZipEntry entry = zipFile.getEntry(entryName);
        InputStream inputStream = zipFile.getInputStream(entry);
        Reader reader = new InputStreamReader(inputStream);
        return reader;
    }

    @Override
    public void rollback(FetchData action, FetchDataResult result, ExecutionContext context)
            throws DispatchException {
    }

    private final class SortedAsIfNumbers implements Comparator<String> {
        @Override
        public int compare(String o1, String o2) {
            if (o1 == null || o1.isEmpty())
                return -1;
            if (o2 == null || o2.isEmpty())
                return 1;
            try {
                BigDecimal o1AsBD = new BigDecimal(o1);
                BigDecimal o2asBD = new BigDecimal(o2);
                return o1AsBD.compareTo(o2asBD);
            } catch (NumberFormatException nfe) {
                LOG.error("NFE on: " + o1 + ", " + o2);
                return 0;
            }
        }
    }
}

@@ -185,16 +185,48 @@
 o.File;%0A
+import java.io.FileInputStream;%0A
 import j
@@ -277,65 +277,8 @@
 am;%0A
-import java.io.InputStreamReader;%0Aimport java.io.Reader;%0A
 impo
@@ -445,39 +445,8 @@
 st;%0A
-import java.util.zip.ZipEntry;%0A
 impo
@@ -479,38 +479,8 @@
 ion;
-%0Aimport java.util.zip.ZipFile;
 %0A%0Aim
@@ -689,16 +689,82 @@
 ogger;%0A%0A
+import ch.lambdaj.group.Group;%0A%0Aimport com.google.inject.Inject;%0A%0A
 import u
@@ -1166,73 +1166,8 @@
 ult;
-%0Aimport ch.lambdaj.group.Group;%0A%0Aimport com.google.inject.Inject;
 %0A%0Apu
@@ -1925,29 +1925,39 @@
         
-Reader reader
+InputStream inputStream
  = getDa
@@ -1962,22 +1962,27 @@
 DataFile
-Reader
+InputStream
 (dataFil
@@ -2043,22 +2043,27 @@
 ce.load(
-reader
+inputStream
 );%0A     
@@ -3446,22 +3446,27 @@
 private 
-Reader
+InputStream
  getData
@@ -3469,22 +3469,27 @@
 DataFile
-Reader
+InputStream
 (File da
@@ -3615,467 +3615,44 @@
     
-ZipFile zipFile = new ZipFile(dataFile);%0A        LOG.info(%22Found %22 + zipFile.size() + %22 entries in zip file%22);%0A        LOG.info(%22First file: %22 + zipFile.entries().nextElement().getName());%0A        String entryName = zipFile.entries().nextElement().getName();%0A        ZipEntry entry = zipFile.getEntry(entryName);%0A        InputStream inputStream = zipFile.getInputStream(entry);%0A        Reader reader = new InputStreamReader(inputStream);%0A        return reader
+return new FileInputStream(dataFile)
 ;%0A  

Use new persistence.