/**
 * Copyright 2011 Ryszard Wiśniewski <brut.alll@gmail.com>
 * Modified Copyright 2015 ZhaoHai <2801045898@qq.com>
 * <p>
 * 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 zhao.arsceditor;

import android.annotation.SuppressLint;
import android.content.Context;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

import zhao.arsceditor.ResDecoder.ARSCCallBack;
import zhao.arsceditor.ResDecoder.ARSCDecoder;
import zhao.arsceditor.ResDecoder.AXMLDecoder;
import zhao.arsceditor.ResDecoder.GetResValues;
import zhao.arsceditor.ResDecoder.data.ResPackage;
import zhao.arsceditor.ResDecoder.data.ResResource;
import zhao.arsceditor.ResDecoder.data.ResTable;
import zhao.arsceditor.ResDecoder.data.ResValuesFile;

final public class AndrolibResources {

    // TODO: dirty static hack. I have to refactor decoding mechanisms.
    public static boolean sKeepBroken = true;

	private Context context;

    // ARSC解析器
    public ARSCDecoder mARSCDecoder;

    // AXML解析器
    public AXMLDecoder mAXMLDecoder;

    // ELF解析器
    // public Elf elfParser;

    private ResPackage pkg;

    public AndrolibResources(Context context) {
        this.context = context;
    }

    // 解析ARSC的方法
    public void decodeARSC(ResTable resTable, ARSCCallBack callback) throws IOException {

        for (ResPackage pkg : resTable.listMainPackages()) {

            System.out.println("Decoding values */* XMLs...");
            for (ResValuesFile valuesFile : pkg.listValuesFiles()) {
                generateValuesFile(valuesFile, callback);
            }
        }
    }

    /**
     * 解析AXML的方法
     *
     * @param AXMLStream
     * @return 返回一个解析后的临时文件对象
     * @throws IOException
     */
    public void decodeAXML(InputStream AXMLStream) throws IOException {
        mAXMLDecoder = AXMLDecoder.read(AXMLStream);
    }

    @SuppressLint("NewApi")
    private void generateValuesFile(ResValuesFile valuesFile, ARSCCallBack callback) throws IOException {
        for (ResResource res : valuesFile.listResources()) {
            if (valuesFile.isSynthesized(res)) {
                continue;
            }
            ((GetResValues) res.getValue()).getResValues(callback, res);
        }
    }

    public ResPackage getFramPackage() {
        return pkg;
    }

    private ResPackage[] getResPackagesFromARSC(ARSCDecoder decoder, InputStream ARSCStream, ResTable resTable,
                                                boolean keepBroken) throws IOException {
        return decoder.decode(decoder, new BufferedInputStream(ARSCStream), false, keepBroken, resTable).getPackages();
    }

    public ResTable getResTable() {
        ResTable resTable = new ResTable(this);
        return resTable;
    }

    public ResTable getResTable(InputStream ARSCStream) throws IOException {
        return getResTable(ARSCStream, true);
    }

    public ResTable getResTable(InputStream ARSCStream, boolean loadMainPkg) throws IOException {
        ResTable resTable = new ResTable(this);
        if (loadMainPkg) {
            loadMainPkg(resTable, ARSCStream);
        }
        return resTable;
    }

    public ResPackage loadMainPkg(ResTable resTable, InputStream ARSCStream) throws IOException {
        System.out.println("Loading resource table...");
        mARSCDecoder = new ARSCDecoder(new BufferedInputStream(ARSCStream), resTable, sKeepBroken);
        ResPackage[] pkgs = getResPackagesFromARSC(mARSCDecoder, ARSCStream, resTable, sKeepBroken);
        ResPackage pkg = null;

        switch (pkgs.length) {
            case 1:
                pkg = pkgs[0];
                break;
            case 2:
                if (pkgs[0].getName().equals("android")) {
                    System.out.println("Skipping \"android\" package group");
                    pkg = pkgs[1];
                } else if (pkgs[0].getName().equals("com.htc")) {
                    System.out.println("Skipping \"htc\" package group");
                    pkg = pkgs[1];
                }
                break;
            default:
                pkg = selectPkgWithMostResSpecs(pkgs);
        }

        if (pkg == null) {
            throw new IOException("Arsc files with zero or multiple packages");
        }

        resTable.addPackage(pkg, true);
        System.out.println("Loaded.");
        return pkg;
    }

    public void pushFramResPackage(ResPackage pkg) {
        this.pkg = pkg;
    }

    public ResPackage selectPkgWithMostResSpecs(ResPackage[] pkgs) throws IOException {
        int id = 0;
        int value = 0;

        for (ResPackage resPackage : pkgs) {
            if (resPackage.getResSpecCount() > value && !resPackage.getName().equalsIgnoreCase("android")) {
                value = resPackage.getResSpecCount();
                id = resPackage.getId();
            }
        }

        // if id is still 0, we only have one pkgId which is "android" -> 1
        return (id == 0) ? pkgs[0] : pkgs[1];
    }
}
