/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ide.common.vectordrawable;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
//import com.sun.org.apache.xml.internal.serialize.OutputFormat;
//import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import java.io.IOException;
import java.io.StringWriter;

/**
 * Generate a Image based on the VectorDrawable's XML content.
 *
 * <p>This class also contains a main method, which can be used to preview a vector drawable file.
 */
public class VdPreview {

    private static final String ANDROID_ALPHA = "android:alpha";
    private static final String ANDROID_AUTO_MIRRORED = "android:autoMirrored";
    private static final String ANDROID_HEIGHT = "android:height";
    private static final String ANDROID_WIDTH = "android:width";
    public static final int MAX_PREVIEW_IMAGE_SIZE = 4096;
    public static final int MIN_PREVIEW_IMAGE_SIZE = 1;

    /**
     * This encapsulates the information used to determine the preview image size.
     * The reason we have different ways here is that both Studio UI and build process need
     * to use this common code path to generate images for vectordrawable.
     * When mUseWidth is true, use {@code mImageMaxDimension} as the maximum
     * dimension value while keeping the aspect ratio.
     * Otherwise, use {@code mImageScale} to scale the image based on the XML's size information.
     */
    public static class TargetSize {
        private boolean mUseWidth;

        private int mImageMaxDimension;
        private float mImageScale;

        private TargetSize(boolean useWidth, int imageWidth, float imageScale) {
            mUseWidth = useWidth;
            mImageMaxDimension = imageWidth;
            mImageScale = imageScale;
        }

        public static TargetSize createSizeFromWidth(int imageWidth) {
            return new TargetSize(true, imageWidth, 0.0f);
        }

        public static TargetSize createSizeFromScale(float imageScale) {
            return new TargetSize(false, 0, imageScale);
        }
    }

    /**
     * Since we allow overriding the vector drawable's size, we also need to keep
     * the original size and aspect ratio.
     */
    public static class SourceSize {
        public int getHeight() {
            return mSourceHeight;
        }

        public int getWidth() {
            return mSourceWidth;
        }

        private int mSourceWidth;
        private int mSourceHeight;
    }


//    /**
//     * @return a format object for XML formatting.
//     */
//    @NonNull
//    private static OutputFormat getPrettyPrintFormat() {
//        OutputFormat format = new OutputFormat();
//        format.setLineWidth(120);
//        format.setIndenting(true);
//        format.setIndent(4);
//        format.setEncoding("UTF-8");
//        format.setOmitComments(true);
//        return format;
//    }

    /**
     * Get the vector drawable's original size.
     */
    public static SourceSize getVdOriginalSize(@NonNull Document document) {
        Element root = document.getDocumentElement();
        SourceSize srcSize = new SourceSize();
        // Update attributes, note that attributes as width and height are required,
        // while others are optional.
        NamedNodeMap attr = root.getAttributes();
        Node nodeAttr = attr.getNamedItem(ANDROID_WIDTH);
        assert nodeAttr != null;
        srcSize.mSourceWidth = parseDimension(0, nodeAttr, false);

        nodeAttr = attr.getNamedItem(ANDROID_HEIGHT);
        assert nodeAttr != null;
        srcSize.mSourceHeight = parseDimension(0, nodeAttr, false);
        return srcSize;
    }

//    /**
//     * The UI can override some properties of the Vector drawable.
//     * In order to override in an uniform way, we re-parse the XML file
//     * and pick the appropriate attributes to override.
//     *
//     * @param document the parsed document of original VectorDrawable's XML file.
//     * @param info incoming override information for VectorDrawable.
//     * @param errorLog log for the parsing errors and warnings.
//     * param srcSize as an output, store the original size of the VectorDrawable
//     * @return the overridden XML file in one string. If exception happens
//     * or no attributes needs to be overriden, return null.
//     */
//    @Nullable
//    public static String overrideXmlContent(@NonNull Document document,
//                                            @NonNull VdOverrideInfo info,
//                                            @Nullable StringBuilder errorLog) {
//        boolean isXmlFileContentChanged = false;
//        Element root = document.getDocumentElement();
//
//        // Update attributes, note that attributes as width and height are required,
//        // while others are optional.
//        NamedNodeMap attr = root.getAttributes();
//        if (info.needsOverrideWidth()) {
//            Node nodeAttr = attr.getNamedItem(ANDROID_WIDTH);
//            int overrideValue = info.getWidth();
//            int originalValue = parseDimension(overrideValue, nodeAttr, true);
//            if (originalValue != overrideValue) {
//                isXmlFileContentChanged = true;
//            }
//        }
//        if (info.needsOverrideHeight()) {
//            Node nodeAttr = attr.getNamedItem(ANDROID_HEIGHT);
//            int overrideValue = info.getHeight();
//            int originalValue = parseDimension(overrideValue, nodeAttr, true);
//            if (originalValue != overrideValue) {
//                isXmlFileContentChanged = true;
//            }
//        }
//        if (info.needsOverrideOpacity()) {
//            Node nodeAttr = attr.getNamedItem(ANDROID_ALPHA);
//            String opacityValue = String.format("%.2f", info.getOpacity() / 100.0f);
//            if (nodeAttr != null) {
//                nodeAttr.setTextContent(opacityValue);
//            }
//            else {
//                root.setAttribute(ANDROID_ALPHA, opacityValue);
//            }
//            isXmlFileContentChanged = true;
//        }
//        // When auto mirror is set to true, then we always need to set it.
//        // Because SVG has no such attribute at all.
//        if (info.needsOverrideAutoMirrored()) {
//            Node nodeAttr = attr.getNamedItem(ANDROID_AUTO_MIRRORED);
//            if (nodeAttr != null) {
//                nodeAttr.setTextContent("true");
//            }
//            else {
//                root.setAttribute(ANDROID_AUTO_MIRRORED, "true");
//            }
//            isXmlFileContentChanged = true;
//        }
//
//        if (isXmlFileContentChanged) {
//            // Prettify the XML string from the document.
//            StringWriter stringOut = new StringWriter();
//            XMLSerializer serial = new XMLSerializer(stringOut, getPrettyPrintFormat());
//            try {
//                serial.serialize(document);
//            }
//            catch (IOException e) {
//                if (errorLog != null) {
//                    errorLog.append("Exception while parsing XML file:\n").append(e.getMessage());
//                }
//            }
//            return stringOut.toString();
//        } else {
//            return null;
//        }
//    }

    /**
     * Query the dimension info and override it if needed.
     *
     * @param overrideValue the dimension value to override with.
     * @param nodeAttr the node who contains dimension info.
     * @param override if true then override the dimension.
     * @return the original dimension value.
     */
    private static int parseDimension(int overrideValue, Node nodeAttr, boolean override) {
        assert nodeAttr != null;
        String content = nodeAttr.getTextContent();
        assert content.endsWith("dp");
        int originalValue = Integer.parseInt(content.substring(0, content.length() - 2));

        if (override) {
            nodeAttr.setTextContent(overrideValue + "dp");
        }
        return originalValue;
    }

//    /**
//     * This generates an image according to the VectorDrawable's content {@code xmlFileContent}.
//     * At the same time, {@vdErrorLog} captures all the errors found during parsing.
//     * The size of image is determined by the {@code size}.
//     *
//     * @param targetSize the size of result image.
//     * @param xmlFileContent  VectorDrawable's XML file's content.
//     * @param vdErrorLog      log for the parsing errors and warnings.
//     * @return an preview image according to the VectorDrawable's XML
//     */
//    @Nullable
//    public static BufferedImage getPreviewFromVectorXml(@NonNull TargetSize targetSize,
//                                                        @Nullable String xmlFileContent,
//                                                        @Nullable StringBuilder vdErrorLog) {
//        if (xmlFileContent == null || xmlFileContent.isEmpty()) {
//            return null;
//        }
//        VdParser p = new VdParser();
//        VdTree vdTree;
//
//        InputStream inputStream = new ByteArrayInputStream(
//                xmlFileContent.getBytes(Charsets.UTF_8));
//        vdTree = p.parse(inputStream, vdErrorLog);
//        if (vdTree == null) {
//            return null;
//        }
//
//        // If the forceImageSize is set (>0), then we honor that.
//        // Otherwise, we will ask the vectorDrawable for the prefer size, then apply the imageScale.
//        float vdWidth = vdTree.getBaseWidth();
//        float vdHeight = vdTree.getBaseHeight();
//        float imageWidth;
//        float imageHeight;
//        int forceImageSize = targetSize.mImageMaxDimension;
//        float imageScale = targetSize.mImageScale;
//
//        if (forceImageSize > 0) {
//            // The goal here is to generate an image within certain size, while keeping the
//            // aspect ration as much as we can.
//            // If it is scaling too much to fit in, we log an error.
//            float maxVdSize = Math.max(vdWidth, vdHeight);
//            float ratioToForceImageSize = forceImageSize / maxVdSize;
//            float scaledWidth = ratioToForceImageSize * vdWidth;
//            float scaledHeight = ratioToForceImageSize * vdHeight;
//            imageWidth = Math.max(MIN_PREVIEW_IMAGE_SIZE, Math.min(MAX_PREVIEW_IMAGE_SIZE, scaledWidth));
//            imageHeight = Math.max(MIN_PREVIEW_IMAGE_SIZE, Math.min(MAX_PREVIEW_IMAGE_SIZE, scaledHeight));
//            if (scaledWidth != imageWidth || scaledHeight != imageHeight) {
//                vdErrorLog.append("Invalid image size, can't fit in a square whose size is" + forceImageSize);
//            }
//        } else {
//            imageWidth = vdWidth * imageScale;
//            imageHeight = vdHeight * imageScale;
//        }
//
//        // Create the image according to the vectorDrawable's aspect ratio.
//
//        BufferedImage image = AssetUtil.newArgbBufferedImage((int)imageWidth, (int)imageHeight);
//        vdTree.drawIntoImage(image);
//        return image;
//    }

    public static void main(String[] args) {
        System.out.println("Hello from sdk-common-lib.");
    }
}