/*
 * 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.kalab.chess.enginesupport;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;

public class ChessEngineResolver {

    private static final String ENGINE_PROVIDER_MARKER = "intent.chess.provider.ENGINE";
    private static final String TAG = ChessEngineResolver.class.getSimpleName();
    private Context context;
    private String target;

    public ChessEngineResolver(Context context) {
        super();
        this.context = context;
        this.target = Build.CPU_ABI;
        sanitizeArmV6Target();
    }

    private void sanitizeArmV6Target() {
        if (this.target.startsWith("armeabi-v6")) {
            this.target = "armeabi";
        }
    }

    public List<ChessEngine> resolveEngines() {
        List<ChessEngine> result = new ArrayList<>();
        final Intent intent = new Intent(ENGINE_PROVIDER_MARKER);
        List<ResolveInfo> list = context.getPackageManager()
                .queryIntentActivities(intent, PackageManager.GET_META_DATA);
        for (ResolveInfo resolveInfo : list) {
            String packageName = resolveInfo.activityInfo.packageName;
            result = resolveEnginesForPackage(result, resolveInfo, packageName);
        }
        return result;
    }

    private List<ChessEngine> resolveEnginesForPackage(
            List<ChessEngine> result, ResolveInfo resolveInfo,
            String packageName) {
        if (packageName != null) {
            Log.d(TAG, "found engine provider, packageName=" + packageName);
            Bundle bundle = resolveInfo.activityInfo.metaData;
            if (bundle != null) {
                String authority = bundle
                        .getString("chess.provider.engine.authority");
                Log.d(TAG, "authority=" + authority);
                if (authority != null) {
                    try {
                        Resources resources = context
                                .getPackageManager()
                                .getResourcesForApplication(
                                        resolveInfo.activityInfo.applicationInfo);
                        int resId = resources.getIdentifier("enginelist",
                                "xml", packageName);
                        XmlResourceParser parser = resources.getXml(resId);
                        parseEngineListXml(parser, authority, result, packageName);
                    } catch (NameNotFoundException e) {
                        Log.e(TAG, e.getLocalizedMessage(), e);
                    }
                }
            }
        }
        return result;
    }

    private void parseEngineListXml(XmlResourceParser parser, String authority,
            List<ChessEngine> result, String packageName) {
        try {
            int eventType = parser.getEventType();
            while (eventType != XmlResourceParser.END_DOCUMENT) {
                String name = null;
                try {
                    if (eventType == XmlResourceParser.START_TAG) {
                        name = parser.getName();
                        if (name.equalsIgnoreCase("engine")) {
                            String fileName = parser.getAttributeValue(null,
                                    "filename");
                            String title = parser.getAttributeValue(null,
                                    "name");
                            String targetSpecification = parser
                                    .getAttributeValue(null, "target");
                            String[] targets = targetSpecification.split("\\|");
                            for (String cpuTarget : targets) {
                                if (target.equals(cpuTarget)) {
                                    result.add(new ChessEngine(title, fileName,
                                            authority, packageName));
                                }
                            }
                        }
                    }
                    eventType = parser.next();
                } catch (IOException e) {
                    Log.e(TAG, e.getLocalizedMessage(), e);
                }
            }
        } catch (XmlPullParserException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
        }
    }

    /**
     * Don't use this in production - this method is only for testing. Set the
     * cpu target.
     * 
     * @param target
     *            the cpu target to set
     */
    public void setTarget(String target) {
        this.target = target;
        sanitizeArmV6Target();
    }
}
