package net.osmand.swing;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

import net.osmand.LogUtil;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager.BeanShellTileSourceTemplate;
import net.osmand.map.TileSourceManager.TileSourceTemplate;

import org.apache.commons.logging.Log;


public class SQLiteBigPlanetIndex {
	private static final Log log = LogUtil.getLog(SQLiteBigPlanetIndex.class);
	
	private static final int BATCH_SIZE = 50;
	
	public static void createSQLiteDatabase(File dirWithTiles, String regionName, ITileSource template) throws SQLException, IOException {
		long now = System.currentTimeMillis();
		try {
			Class.forName("org.sqlite.JDBC"); //$NON-NLS-1$
		} catch (ClassNotFoundException e) {
			log.error("Illegal configuration", e); //$NON-NLS-1$
			throw new IllegalStateException(e);
		}
		File fileToWrite = new File(dirWithTiles, regionName + "." + template.getName() + ".sqlitedb");
		fileToWrite.delete();
		Connection conn = DriverManager.getConnection("jdbc:sqlite:" + fileToWrite.getAbsolutePath()); //$NON-NLS-1$
		Statement statement = conn.createStatement();
		statement.execute("CREATE TABLE tiles (x int, y int, z int, s int, image blob, PRIMARY KEY (x,y,z,s))");
		statement.execute("CREATE INDEX IND on tiles (x,y,z,s)");
		statement.execute("CREATE TABLE info(minzoom,maxzoom,url)");
		statement.execute("CREATE TABLE android_metadata (locale TEXT)");
		statement.close();
		

		PreparedStatement pStatement = conn.prepareStatement("INSERT INTO INFO VALUES(?,?,?)");
		if (template instanceof TileSourceTemplate && !(template instanceof BeanShellTileSourceTemplate)) {
			pStatement.setInt(1, template.getMinimumZoomSupported());
			pStatement.setInt(2, template.getMaximumZoomSupported());
			pStatement.setString(3, ((TileSourceTemplate) template).getUrlTemplate());
			pStatement.execute();
		}
		pStatement.close();
		

		conn.setAutoCommit(false);
		pStatement = conn.prepareStatement("INSERT INTO tiles VALUES (?, ?, ?, ?, ?)");
		int ch = 0;
		// be attentive to create buf enough for image 
		int bufSize = 32 * 1024;
		byte[] buf = new byte[bufSize];
		int maxZoom = 17;
		int minZoom = 1;
		
		File rootDir = new File(dirWithTiles, template.getName());
		for(File z : rootDir.listFiles()){
			try {
				int zoom = Integer.parseInt(z.getName());
				for(File xDir : z.listFiles()){
					try {
						int x = Integer.parseInt(xDir.getName());
						for(File f : xDir.listFiles()){
							if(!f.isFile()){
								continue;
							}
							try {
								int i = f.getName().indexOf('.');
								int y = Integer.parseInt(f.getName().substring(0, i));
								buf = new byte[(int) f.length()]; 
								if(zoom > maxZoom){
									maxZoom = zoom;
								}
								if(zoom < minZoom){
									minZoom = zoom;
								}
								
								FileInputStream is = new FileInputStream(f);
								int l = 0;
								try {
									l = is.read(buf);
								} finally {
									is.close();
								}
								if (l > 0) {
									pStatement.setInt(1, x);
									pStatement.setInt(2, y);
									pStatement.setInt(3, 17 - zoom);
									pStatement.setInt(4, 0);
									pStatement.setBytes(5, buf);
									pStatement.addBatch();
									ch++;
									if (ch >= BATCH_SIZE) {
										pStatement.executeBatch();
										ch = 0;
									}
								}
							
							} catch (NumberFormatException e) {
							}
						}
					} catch (NumberFormatException e) {
					}
				}
				
			} catch (NumberFormatException e) {
			}
			
		}
		
		if (ch > 0) {
			pStatement.executeBatch();
			ch = 0;
		}
		
		pStatement.close();
		conn.commit();
		conn.close();
		log.info("Index created " + fileToWrite.getName() + " " + (System.currentTimeMillis() - now) + " ms");
	}

}
