package net.informaticalibera.tests.goldeneditor;

import com.codename1.io.Log;
import com.codename1.ui.Display;
import com.codename1.ui.Font;
import com.codename1.ui.plaf.RoundRectBorder;
import com.codename1.ui.plaf.Style;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;

public class DeviceUtilities {
    
    private static int percentage = calculateAdaptionPercentage();
    
       /**
     * Loads the given CSS, adjusting its values to the width of the screen.
     *
     * @param css file name, WITHOUT SLASHES AND WITHOUT .css EXTENSION!!!
     */
    public static void loadCSS(String css) {
        try {
            UIManager.initFirstTheme("/" + css);
            Resources resource = Resources.openLayered("/" + css);

            Hashtable themeProps = resource.getTheme("Theme");

            UIManager.getInstance().setThemeProps(adaptTheme(themeProps));
            Resources.setGlobalResources(resource);

            Log.p("Loaded " + css + ".css", Log.DEBUG);
        } catch (Exception ex) {
            Log.p("CssUtilities.loadCSS - ERROR", Log.ERROR);
            Log.e(ex);
            Log.sendLogAsync();
        }
    }

    /**
     * Calculate the percentage to adapt the font sizes to the screen width. The
     * maximum decrease of the sizes is about 30%, increasing is disabled.
     *
     * @return percentage from -30 to 0
     */
    private static int calculateAdaptionPercentage() {
        // 62 mm is the actual screen width of iPhone X (correctly detected by Codename One)
        int defaultScreenWidth = Display.getInstance().convertToPixels(62);
        int currentScreenWidth = Display.getInstance().getDisplayWidth();
        int currentInMM = currentScreenWidth / Display.getInstance().convertToPixels(1);

        int percentage = currentScreenWidth * 100 / defaultScreenWidth - 100;
        if (percentage < -30) {
            percentage = -30;
        } else if (percentage > 0) {
            percentage = 0;
        }

        Log.p("Estimated screen width: " + currentInMM + " mm", Log.INFO);
        Log.p("Font percentage: " + percentage + "%", Log.INFO);
        return percentage;
    }

    /**
     * Modify a theme changing the font sizes, margins and paddings
     *
     * @param themeProps
     * @return the new theme
     */
    private static Hashtable adaptTheme(Hashtable hashtable) {
        Hashtable<String, Object> result = new Hashtable<>();
        Set<String> keys = hashtable.keySet();
        Iterator<String> itr = keys.iterator();
        String key;
        Object value;
        while (itr.hasNext()) {
            key = itr.next();
            value = hashtable.get(key);
            // Log.p("key: " + key + ", value is: " + value.getClass().getName() + ", " + value.toString());
            if (value instanceof Font && ((Font) value).isTTFNativeFont() && percentage < 0) {
                Font font = (Font) value;
                float newSize = (int) (font.getPixelSize() * (100 + percentage) / 100);
                result.put(key, font.derive(newSize, font.getStyle()));
            } else if (key.endsWith("#margin") || key.endsWith(".margin")
                    || key.endsWith("#padding") || key.endsWith(".padding")) {
                if (value instanceof String) {
                    // Log.p("input:  " + value);
                    // Log.p("output: " + resizeMarginPadding((String) value));
                    result.put(key, resizeMarginPadding((String) value));
                }
            } else {
                result.put(key, value);
            }
        }
        return result;
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @return
     */
    public static int getResized(int size) {
        return size * (100 + percentage) / 100;
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @return
     */
    public static float getResized(double size) {
        return (float) (size * (100 + percentage) / 100);
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @param convertToPx if true, convert the given size from mm to pixels
     * @return
     */
    public static int getResized(int size, boolean convertToPx) {
        if (!convertToPx) {
            return getResized(size);
        } else {
            return getResized(Display.getInstance().convertToPixels(size));
        }
    }

    /**
     * Resizes the given margin or the padding
     *
     * @param input in a form like 0.0,1.0,0.9,15.0
     * @return the given input if it's not a valid margin or padding, or a new
     * String with the margins or paddings recalculated
     */
    private static String resizeMarginPadding(String input) {
        String result = "";

        StringTokenizer st = new StringTokenizer(input, ",");
        // Do we have 4 numbers?
        if (st.countTokens() == 4) {
            while (st.hasMoreTokens()) {
                // Is this token a number like 1.5, 0.0, etc.?
                String token = st.nextToken();
                try {
                    Float number = Float.valueOf(token);
                    number = getResized(number);
                    number = ((int) (number * 10)) / 10.0f;
                    result += number;
                    if (st.countTokens() != 0) {
                        result += ",";
                    }
                } catch (NumberFormatException e) {
                    return input;
                }
            }
        } else {
            return input;
        }

        return result;
    }

    /**
     * Returns a resized dimension (like a width or height)
     *
     * @param size, the unit of measurement (px, mm, pt, etc.) does not matter
     * @param convertToPx if true, convert the given size from mm to pixels
     * @return
     */
    public static double getResized(double size, boolean convertToPx) {
        if (!convertToPx) {
            return getResized(size);
        } else {
            return getResized(Display.getInstance().convertToPixels((float) size));
        }
    }

}
