/*
 * Copyright (C) 2017 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.cts.verifier.audio.peripheralprofile;

import android.media.AudioDeviceInfo;
import androidx.annotation.NonNull;

import com.android.cts.verifier.audio.peripheralprofile.ListsHelper;

import java.io.IOException;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class PeripheralProfile extends DefaultHandler {
    private String mProfileName;
    private String mProfileDescription;

    private String mProductName = "";    // From AudioDeviceInfo

    public class ProfileAttributes {
        public int[] mChannelCounts;
        public int[] mChannelIndexMasks;
        public int[] mChannelPositionMasks;
        public int[] mEncodings;
        public int[] mSampleRates;
    }

    ProfileAttributes mOutputAttributes;
    ProfileAttributes mInputAttributes;

    ProfileButtonAttributes mButtonAttributes;

    //
    // Accessors
    //
    public String getName() { return mProfileName; }
    public String getDescription() { return mProfileDescription; }
    public String getProductName() { return mProductName; }

    public ProfileAttributes getOutputAttributes() {
        return mOutputAttributes;
    }
    public ProfileAttributes getInputAttributes() {
        return mInputAttributes;
    }
    public ProfileButtonAttributes getButtonAttributes() {
        return mButtonAttributes;
    }

    @Override
    public String toString() { return mProfileName; }

    public PeripheralProfile(String profileName, String profileDescription,
                             AudioDeviceInfo outDeviceInfo,
                             AudioDeviceInfo inDeviceInfo,
                             ProfileButtonAttributes buttonAttributes) {
        mProfileName = profileName;
        mProfileDescription = profileDescription;

        if (outDeviceInfo != null) {
            mProductName = outDeviceInfo.getProductName().toString();

            mOutputAttributes = new ProfileAttributes();
            mOutputAttributes.mChannelCounts =
                outDeviceInfo.getChannelCounts();
            mOutputAttributes.mChannelIndexMasks =
                outDeviceInfo.getChannelIndexMasks();
            mOutputAttributes.mChannelPositionMasks =
                outDeviceInfo.getChannelMasks();
            mOutputAttributes.mEncodings = outDeviceInfo.getEncodings();
            mOutputAttributes.mSampleRates = outDeviceInfo.getSampleRates();
        } else {
            mOutputAttributes = null;
        }

        if (inDeviceInfo != null) {
            mProductName = outDeviceInfo.getProductName().toString();

            mInputAttributes = new ProfileAttributes();
            mInputAttributes.mChannelCounts = inDeviceInfo.getChannelCounts();
            mInputAttributes.mChannelIndexMasks = inDeviceInfo.getChannelIndexMasks();
            mInputAttributes.mChannelPositionMasks = inDeviceInfo.getChannelMasks();
            mInputAttributes.mEncodings = inDeviceInfo.getEncodings();
            mInputAttributes.mSampleRates = inDeviceInfo.getSampleRates();
        } else {
            mInputAttributes = null;
        }

        mButtonAttributes = buttonAttributes;
    }

    public static boolean matches(ProfileAttributes attribs, AudioDeviceInfo deviceInfo) {
        boolean match =
            ListsHelper.isMatch(deviceInfo.getChannelCounts(), attribs.mChannelCounts) &&
            ListsHelper.isMatch(deviceInfo.getChannelIndexMasks(), attribs.mChannelIndexMasks) &&
            ListsHelper.isMatch(deviceInfo.getChannelMasks(), attribs.mChannelPositionMasks) &&
            ListsHelper.isMatch(deviceInfo.getEncodings(), attribs.mEncodings) &&
            ListsHelper.isMatch(deviceInfo.getSampleRates(), attribs.mSampleRates);
        return match;
    }

    //
    // Peripheral (XML) Loading
    //
    private static int[] parseIntList(String intList) {
        String[] strings = intList.split(",");
        int[] ints = new int[strings.length];
        for (int index = 0; index < strings.length; index++) {
            try {
                ints[index] = Integer.parseInt(strings[index]);
            }
            catch (NumberFormatException ex) {
                ints[index] = 0;
            }
        }
        return ints;
    }

    // XML Tags
    public static final String kTag_Profile = "PeripheralProfile";
    public static final String kTag_OutputDevInfo = "OutputDevInfo";
    public static final String kTag_InputDevInfo = "InputDevInfo";
    public static final String kTag_ButtonInfo = "ButtonInfo";

    // XML Attributes
    //  - Attributes for Profile Tag
    private static final String kAttr_ProfileName = "ProfileName";
    private static final String kAttr_ProfileDescription = "ProfileDescription";
    private static final String kAttr_Product = "ProductName";

    //  - Attributes for DevInfo tags
    private static final String kAttr_ChanCounts = "ChanCounts";
    private static final String kAttr_ChanPosMasks = "ChanPosMasks";
    private static final String kAttr_ChanIndexMasks = "ChanIndexMasks";
    private static final String kAttr_Encodings = "Encodings";
    private static final String kAttr_SampleRates = "SampleRates";
    private static final String kAttr_HasBtnA = "HasBtnA";
    private static final String kAttr_HasBtnB = "HasBtnB";
    private static final String kAttr_HasBtnC = "HasBtnC";

    private void parseProfileAttributes(ProfileAttributes attribs, String elementName,
                                        Attributes xmlAtts) {
        attribs.mChannelCounts = parseIntList(xmlAtts.getValue(kAttr_ChanCounts));
        attribs.mChannelPositionMasks = parseIntList(xmlAtts.getValue(kAttr_ChanPosMasks));
        attribs.mChannelIndexMasks = parseIntList(xmlAtts.getValue(kAttr_ChanIndexMasks));
        attribs.mEncodings = parseIntList(xmlAtts.getValue(kAttr_Encodings));
        attribs.mSampleRates = parseIntList(xmlAtts.getValue(kAttr_SampleRates));
    }

    private void parseProfileButtons(ProfileButtonAttributes buttonAttributes, String elementName,
                                     Attributes xmlAtts) {
        buttonAttributes.mHasBtnA = Integer.parseInt(xmlAtts.getValue(kAttr_HasBtnA)) == 1;
        buttonAttributes.mHasBtnB = Integer.parseInt(xmlAtts.getValue(kAttr_HasBtnB)) == 1;
        buttonAttributes.mHasBtnC = Integer.parseInt(xmlAtts.getValue(kAttr_HasBtnC)) == 1;
    }

    //
    // org.xml.sax.helpers.DefaultHandler overrides
    //
    @Override
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
        if (qName.equals(kTag_Profile)) {
            mProfileName = atts.getValue(kAttr_ProfileName);
            mProfileDescription = atts.getValue(kAttr_ProfileDescription);
            mProductName = atts.getValue(kAttr_Product);
        } else if (qName.equals(kTag_OutputDevInfo)) {
            mOutputAttributes = new ProfileAttributes();
            parseProfileAttributes(mOutputAttributes, localName, atts);
        } else if (qName.equals(kTag_InputDevInfo)) {
            mInputAttributes = new ProfileAttributes();
            parseProfileAttributes(mInputAttributes, localName, atts);
        } else if (qName.equals(kTag_ButtonInfo)) {
            mButtonAttributes = new ProfileButtonAttributes();
            parseProfileButtons(mButtonAttributes, localName, atts);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) {
    }
}
