package org.openstreetmap.josm.plugins.dataimport.io;

import static org.openstreetmap.josm.tools.I18n.tr;

import com.garmin.fit.*;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.ExtensionFileFilter;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.gpx.GpxData;
import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
import org.openstreetmap.josm.data.gpx.WayPoint;
import org.openstreetmap.josm.gui.layer.GpxLayer;
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
import org.openstreetmap.josm.io.FileImporter;
import org.openstreetmap.josm.io.IllegalDataException;
import org.openstreetmap.josm.tools.Utils;

public class Fit extends FileImporter {

    public Fit() {
        super(new ExtensionFileFilter("fit", "fit",
                tr("Flexible and Interoperable Data Transfer Files (*.fit)")));
    }

    public static GpxData toGpxData(InputStream fit) {
        final Collection<WayPoint> track = new ArrayList<WayPoint>();

        final Decode decode = new Decode();
        decode.addListener(new MesgListener() {

            private Number semicircleToDegree(Field field) {
                if (field != null && "semicircles".equals(field.getUnits())) {
                    final long semicircle = field.getLongValue();
                    return semicircle / Double.valueOf(1L << 31) * 180;
                } else {
                    return null;
                }
            }

            @Override
            public void onMesg(Mesg mesg) {

                Main.debug(Utils.transform(mesg.getFields(), new Utils.Function<Field, String>() {

                    @Override
                    public String apply(Field x) {
                        return x.getName() + "=" + x.getStringValue();
                    }

                }).toString());

                final Number lat = semicircleToDegree(mesg.getField("position_lat"));
                final Number lon = semicircleToDegree(mesg.getField("position_long"));

                if (lat != null && lon != null) {
                    final WayPoint wp = new WayPoint(new LatLon(lat.doubleValue(), lon.doubleValue()));
                    wp.attr.put("time", mesg.getFieldStringValue("timestamp"));
                    wp.attr.put("ele", mesg.getFieldStringValue("altitude"));
                    wp.attr.put("speed", mesg.getFieldStringValue("speed"));
                    wp.setTime();
                    track.add(wp);
                }

            }
        });
        decode.read(fit);

        final GpxData data = new GpxData();
        data.tracks.add(new ImmutableGpxTrack(
                Collections.singleton(track),
                Collections.<String, Object>emptyMap()
        ));

        return data;
    }

    @Override
    public void importData(File file, ProgressMonitor progressMonitor) throws IOException, IllegalDataException {
        final GpxData gpxData = toGpxData(new BufferedInputStream(new FileInputStream(file)));
        gpxData.storageFile = file;
        GpxLayer gpxLayer = new GpxLayer(gpxData, file.getName());
        Main.main.addLayer(gpxLayer);
    }

}
