/*
 * 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.android.ide.common.blame.SourcePosition;
import com.android.utils.PositionXmlParser;
import com.google.common.base.Strings;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Represent the SVG file in an internal data structure as a tree.
 */
public class SvgTree {
    private static Logger logger = Logger.getLogger(SvgTree.class.getSimpleName());

    public float w;
    public float h;
    public float[] matrix;
    public float[] viewBox;
    public float mScaleFactor = 1;

    private SvgGroupNode mRoot;
    private String mFileName;

    private ArrayList<String> mErrorLines = new ArrayList<String>();

    public enum SvgLogLevel {
        ERROR,
        WARNING
    }

    public Document parse(File f) throws Exception {
        mFileName = f.getName();
        Document doc = PositionXmlParser.parse(new FileInputStream(f), false);
        return doc;
    }

    public void normalize() {
        if (matrix != null) {
            transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
        }

        if (viewBox != null && (viewBox[0] != 0 || viewBox[1] != 0)) {
            transform(1, 0, 0, 1, -viewBox[0], -viewBox[1]);
        }
        logger.log(Level.FINE, "matrix=" + Arrays.toString(matrix));
    }

    private void transform(float a, float b, float c, float d, float e, float f) {
        mRoot.transform(a, b, c, d, e, f);
    }

    public void dump(SvgGroupNode root) {
        logger.log(Level.FINE, "current file is :" + mFileName);
        root.dumpNode("");
    }

    public void setRoot(SvgGroupNode root) {
        mRoot = root;
    }

    @Nullable
    public SvgGroupNode getRoot() {
        return mRoot;
    }

    public void logErrorLine(String s, Node node, SvgLogLevel level) {
        if (!Strings.isNullOrEmpty(s)) {
            if (node != null) {
                SourcePosition position = getPosition(node);
                mErrorLines.add(level.name() + "@ line " + (position.getStartLine() + 1) +
                                " " + s + "\n");
            } else {
                mErrorLines.add(s);
            }
        }
    }

    /**
     * @return Error log. Empty string if there are no errors.
     */
    @NonNull
    public String getErrorLog() {
        StringBuilder errorBuilder = new StringBuilder();
        if (!mErrorLines.isEmpty()) {
            errorBuilder.append("In " + mFileName + ":\n");
        }
        for (String log : mErrorLines) {
            errorBuilder.append(log);
        }
        return errorBuilder.toString();
    }

    /**
     * @return true when there is no error found when parsing the SVG file.
     */
    public boolean canConvertToVectorDrawable() {
        return mErrorLines.isEmpty();
    }

    private SourcePosition getPosition(Node node) {
        return PositionXmlParser.getPosition(node);
    }

}
