package me.hammerle.supersnuvi.savegame;

import java.io.File;
import java.io.IOException;
import java.nio.charset.MalformedInputException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class SimpleConfig
{            
    protected final TreeMap<String, Object> conf;
    private final File file;
    
    public SimpleConfig(String path)
    {    
        file = new File(path);
        conf = new TreeMap<>();
    }
    
    private Object convertInput(String s)
    {
        if(s.equals("true"))
        {
            return true;
        }
        else if(s.equals("false"))
        {
            return false;
        }
        try
        {
            return Integer.parseInt(s);
        }
        catch(NumberFormatException ex)
        {
            try
            {
                return Double.parseDouble(s);
            }
            catch(NumberFormatException ex2)
            {
            }
        }
        return s;
    }
    
    public final void load()
    {
        if(!exists())
        {
            return;
        }
        try
        {
            String warning = "wrong syntax in '" + file.getPath() + "'";
            Files.readAllLines(file.toPath()).stream().forEach(s -> 
            {
                int b = s.indexOf("=");
                if(b == -1)
                {
                    System.err.println(warning);
                    System.err.println(s);
                }
                else
                {
                    conf.put(s.substring(0, b).trim(), convertInput(s.substring(b + 1)));
                }
            });
        } 
        catch(MalformedInputException ex) 
        {
            System.err.println("'" + file.getPath() + "' contains an illegal character, change file encoding");
        }
        catch(OutOfMemoryError ex) 
        {
            System.err.println("'" + file.getPath() + "' is too big");
        }
        catch(SecurityException ex) 
        {
            System.err.println("'" + file.getPath() + "' is not accessable");
            System.err.println(ex.getMessage());
        }
        catch(IOException ex) 
        {
            System.err.println("'" + file.getPath() + "' cannot be read");
            System.err.println(ex.getMessage());
        }
    }   
    
    public final boolean exists()
    {
        return file.exists();
    }
    
    public final boolean delete()
    {
        return file.delete();
    }
    
    public final boolean save()
    {
        try
        {
            if(file.getParentFile() != null)
            {
                file.getParentFile().mkdirs();
            }
            if(!file.exists())
            {
                try
                {
                    file.createNewFile();
                }
                catch(IOException ex)
                {
                    System.err.println("'" + file.getPath() + "' cannot be created");
                    System.err.println(ex.getMessage());
                    return false;
                }
            }
            Files.write(Paths.get(file.toURI()), conf.entrySet().stream()
                            .map(e -> 
                            {
                                if(e.getValue().getClass() == String.class)
                                {
                                    return e.getKey() + "=\"" + e.getValue() + "\"";
                                }
                                return e.getKey() + "=" + String.valueOf(e.getValue());
                            })
                            .collect(Collectors.toList()), StandardCharsets.UTF_8);
            return true;
        }
        catch(UnsupportedOperationException ex)
        {
            System.err.println("an unsupported operation was used");
            System.err.println(ex.getMessage());
            return false;
        }
        catch(SecurityException ex)
        {
            System.err.println("'" + file.getPath() + "' is not accessable");
            System.err.println(ex.getMessage());
            return false;
        }
        catch(IOException ex)
        {
            System.err.println("cannot write to '" + file.getPath() + "'");
            System.err.println(ex.getMessage());
            return false;
        }
    }
    
    // -------------------------------------------------------------------------
    // getter
    // -------------------------------------------------------------------------
    
    public final <T> T get(String key, Class<T> c, T error)
    {
        try
        {
            Object o = conf.get(key);
            if(o == null)
            {
                return error;
            }
            return c.cast(o);
        }
        catch(ClassCastException ex)
        {
            return error;
        }
    }
    
    public final String getString(String key, String error)
    {
        return get(key, String.class, error);
    }
    
    public final String getString(String key)
    {
        return getString(key, null);
    }
    
    public final float getFloat(String key, float error)
    {
        return get(key, Number.class, error).floatValue();
    }
    
    public final double getDouble(String key, double error)
    {
        return get(key, Number.class, error).doubleValue();
    }
    
    public final int getInt(String key, int error)
    {
        return get(key, Number.class, error).intValue();
    }
    
    public final boolean getBoolean(String key, boolean error)
    {
        return get(key, Boolean.class, error);
    }
    
    // -------------------------------------------------------------------------
    // set
    // -------------------------------------------------------------------------
    
    public final void set(String key, Object o)
    {
        conf.put(key, o);
    }
}
