package de.cb_map.database.OSMDB;

import de.cb_map.CONSTANTS;
import de.cb_map.database.IElementStreamReader;
import de.cb_map.io.utils.TimeFormat;
import de.cb_map.osm.low_memory.IntBoundingBox;
import de.cb_map.osm.low_memory.ReadOsm;
import org.junit.Test;
import org.mapsforge.map.writer.model.TDNode;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
 * Created by Longri on 30.03.2016.
 */
public class FileOSMDBTest {
    static final String dbPath = CONSTANTS.RESOURCE;
    static final String dbName = "testDatabase";
    static final String dbName2 = "testDatabase2";
    static final String dbName3 = "testDatabase3";
    static final String dbName4 = "testDatabase4";

    @Test
    public void create() throws Exception {

        //delete exist db file
        FileOSMDB.delete(dbPath, dbName);

        FileOSMDB db = new FileOSMDB(dbPath, dbName, AccessType.WRITE);
        db.open();

        FileOSMDB db2 = new FileOSMDB(dbPath, dbName, AccessType.READ);
        db2.open();

        //db2 must read default header settings

        //  assertEquals("Wrong NodeStore pointer", FileOSMDB.HEADER_LENGTH + 1, db2.POINTER.NodeStore);

    }

    @Test
    public void addNodeAndSearch() throws Exception {

        //delete exist db file
        FileOSMDB.delete(dbPath, dbName2);

        FileOSMDB db = new FileOSMDB(dbPath, dbName2, AccessType.READ_WRITE);
        db.open();

        TDNode node = new TDNode(1, 10, -11, (short) 1, (byte) 1, "Housenumber", "Name", new short[]{1, 2});
        db.storeNode(node, true);
        TDNode node2 = db.getNode(1);

        TDNode node3 = new TDNode(2, 2, 2, (short) 2, (byte) 2, "Housenumber2", "Name2", new short[]{1, 2});
        db.storeNode(node3, true);
        TDNode node4 = db.getNode(2);

        TDNode node5 = new TDNode(3, 3, 3, (short) 3, (byte) 3, "Housenumber3", "Name3", new short[]{1, 2});
        db.storeNode(node5, true);
        TDNode node6 = db.getNode(3);

        TDNode node7 = new TDNode(4, 4, 4, (short) 5, (byte) 4, "Housenumber4", "Name4", new short[]{1, 2});
        db.storeNode(node7, true);
        TDNode node8 = db.getNode(4);

        // Id equals
        assertEquals("Nodes must by equals", node, node2);
        assertEquals("Nodes must by equals", node3, node4);
        assertEquals("Nodes must by equals", node5, node6);
        assertEquals("Nodes must by equals", node7, node8);

        // latitude equals
        assertEquals("Nodes must by equals", node.getLatitude(), node2.getLatitude());
        assertEquals("Nodes must by equals", node3.getLatitude(), node4.getLatitude());
        assertEquals("Nodes must by equals", node5.getLatitude(), node6.getLatitude());
        assertEquals("Nodes must by equals", node7.getLatitude(), node8.getLatitude());

        // longitude equals
        assertEquals("Nodes must by equals", node.getLongitude(), node2.getLongitude());
        assertEquals("Nodes must by equals", node3.getLongitude(), node4.getLongitude());
        assertEquals("Nodes must by equals", node5.getLongitude(), node6.getLongitude());
        assertEquals("Nodes must by equals", node7.getLongitude(), node8.getLongitude());

    }


    @Test
    public void writeBerlinNodesIntoOSMDB() throws IOException, SQLException {
        boolean onlyRead = false;

        boolean onlyWrite = false;

        File nameFile = new File("src/test/resources/berlin-latest.osm");

        //delete exist db file
        if (!onlyRead) FileOSMDB.delete(dbPath, dbName3);


        long start = System.currentTimeMillis();
        if (!onlyRead) {
            FileOSMDB db = new FileOSMDB(dbPath, dbName3, AccessType.WRITE);
            db.open();
            ReadOsm.setOsmFile(nameFile);
            ReadOsm.writeToGeoDB(db, null);
            long writeTime = System.currentTimeMillis() - start;
            System.out.println("Nodes Write to DB after " + new TimeFormat(writeTime, TimeFormat.ROUND_TO_MILLISECOND));
            System.out.println("Write " + db.count);
            System.out.println("ReadOsmFoundedStartTags " + ReadOsm.nodeCount);
            assertTrue(4323871 == db.count);

        }


        if (onlyWrite) return;

        start = System.currentTimeMillis();

        FileOSMDB DbReader = new FileOSMDB(dbPath, dbName3, AccessType.READ);
        DbReader.open();
        IntBoundingBox bb = new IntBoundingBox(CONSTANTS.BB_PANKOW);
        IElementStreamReader reader = DbReader.getStreamReader(bb);

        int count = 0;
        while (reader.hasNextNode()) {
            reader.getNode();
            count++;
        }


        System.out.println("countAddNode = " + FileOSMDB.countAddNode);
        System.out.println("countAddValues = " + FileOSMDB.countAddValues);
        System.out.println("countAddInside = " + FileOSMDB.countAddInside);
        System.out.println("countRead = " + FileOSMDB.countRead);
        System.out.println("countReadLatLon = " + FileOSMDB.countReadLatLon);
        System.out.println("countAll = " + FileOSMDB.countAll);


        assertEquals("Must found 169 Nodes for PankowBB", 169, count);
        long duration = System.currentTimeMillis() - start;
        System.out.println(count + " Nodes Found in Pankow (" + CONSTANTS.BB_PANKOW + ") after " + new TimeFormat(duration, TimeFormat.ROUND_TO_MILLISECOND));
    }

    @Test
    public void parselatLonTest() throws IOException, SQLException {

        File nameFile = new File("src/test/resources/nodes.osm");

        //delete exist db file
        FileOSMDB.delete(dbPath, dbName4);


        long start = System.currentTimeMillis();

        FileOSMDB db = new FileOSMDB(dbPath, dbName4, AccessType.WRITE);
        db.open();
        ReadOsm.setOsmFile(nameFile);
        ReadOsm.writeToGeoDB(db, null);
        long writeTime = System.currentTimeMillis() - start;
        System.out.println("Nodes Write to DB after " + new TimeFormat(writeTime, TimeFormat.ROUND_TO_MILLISECOND));
        System.out.println("Write " + db.count);
        System.out.println("ReadOsmFoundedStartTags " + ReadOsm.nodeCount);
        assertTrue(10 == db.count);


        start = System.currentTimeMillis();

        FileOSMDB DbReader = new FileOSMDB(dbPath, dbName4, AccessType.READ);
        DbReader.open();
        IntBoundingBox bb = new IntBoundingBox(CONSTANTS.BB_PANKOW);
        IElementStreamReader reader = DbReader.getStreamReader(bb);

        int count = 0;
        while (reader.hasNextNode()) {
            reader.getNode();
            count++;
        }


        System.out.println("countAddNode = " + FileOSMDB.countAddNode);
        System.out.println("countAddValues = " + FileOSMDB.countAddValues);
        System.out.println("countAddInside = " + FileOSMDB.countAddInside);
        System.out.println("countRead = " + FileOSMDB.countRead);
        System.out.println("countReadLatLon = " + FileOSMDB.countReadLatLon);
        System.out.println("countAll = " + FileOSMDB.countAll);


        assertEquals("Must found 0 Nodes for PankowBB", 0, count);
        long duration = System.currentTimeMillis() - start;
        System.out.println(count + " Nodes Found in Pankow (" + CONSTANTS.BB_PANKOW + ") after " + new TimeFormat(duration, TimeFormat.ROUND_TO_MILLISECOND));
    }

}