/*******************************************************************************
 * Copyright (c) 2010, 2018 Red Hat, Inc.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Red Hat - initial API and implementation
 *******************************************************************************/
package org.eclipse.linuxtools.oprofile.core.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.linuxtools.internal.oprofile.core.opxml.modeldata.ModelDataAdapter;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.FrameworkUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Test cases for checking validity of the model data parsed from oprofile that
 * is modified to mimic the XML format expected by the SAX parser.
 * The oprofile module must be loaded and the driver interface must be
 * available. ie. run opcontrol --init
 */
public class TestModelDataPreParse {

    private static final String REL_PATH_TO_MODEL_DATA_RAW = "resources/test_model-data_raw.xml";
    private static final String REL_PATH_TO_MODEL_DATA_EXPECTED = "resources/test_model-data_expected.xml";

    ModelDataAdapter mda;
    Element [] rootList;
    ArrayList<ArrayList<String>> valueList;

    @Before
    public void setUp (){
        String absFilePath;
        Path filePath = new Path(REL_PATH_TO_MODEL_DATA_RAW);
        URL fileURL = FileLocator.find(FrameworkUtil.getBundle(this.getClass()), filePath, null);

        try {
            absFilePath = FileLocator.toFileURL(fileURL).getFile();
            File file = new File (absFilePath);
            FileInputStream inp = new FileInputStream(file);
            mda = new ModelDataAdapter(inp);
            mda.process();
        } catch (IOException e) {
            e.printStackTrace();
        }

        mda.process();
        Document actualDocument = mda.getDocument();
        Element actualRoot = (Element) actualDocument.getElementsByTagName(ModelDataAdapter.MODEL_DATA).item(0);

        filePath = new Path(REL_PATH_TO_MODEL_DATA_EXPECTED);
        fileURL = FileLocator.find(FrameworkUtil.getBundle(this.getClass()), filePath, null);
        Element expectedRoot = null;

        try {
            absFilePath = FileLocator.toFileURL(fileURL).getFile();
            File file = new File (absFilePath);
            FileInputStream inp = new FileInputStream(file);
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder;
            builder = factory.newDocumentBuilder();
            Document expectedDocument = builder.parse(inp);
            expectedRoot = (Element) expectedDocument.getElementsByTagName(ModelDataAdapter.MODEL_DATA).item(0);
        } catch (FileNotFoundException e) {
            fail("File was not found.");
        } catch (IOException e) {
            fail("Failed to convert the resource file's path.");
        } catch (SAXException e) {
            fail("Failed to parse the XML.");
        } catch (ParserConfigurationException e) {
            fail("Failed to create a document builder.");
        }

        rootList = new Element [] {expectedRoot, actualRoot};
        valueList = new ArrayList<> ();

        for (int i = 0; i < rootList.length; i++){
            valueList.add(new ArrayList<String>());
        }
    }

    @Test
    public void testBasic (){
        final String [] imageAttrs = new String [] {ModelDataAdapter.NAME, ModelDataAdapter.COUNT};
        final String [] symbolAttrs = new String [] {ModelDataAdapter.NAME, ModelDataAdapter.FILE, ModelDataAdapter.COUNT};
        final String [] sampleTags = new String [] {ModelDataAdapter.COUNT, ModelDataAdapter.LINE};

        for (int i = 0; i < rootList.length; i++){
            Element imageTag = (Element) rootList[i].getElementsByTagName(ModelDataAdapter.IMAGE).item(0);
            // image name, count
            for (int j = 0; j < imageAttrs.length; j++){
                String attr = imageTag.getAttribute(imageAttrs[j]);
                valueList.get(i).add(attr);
            }

            Element symbolsTag = (Element) rootList[i].getElementsByTagName(ModelDataAdapter.SYMBOLS).item(0);
            NodeList symbolList = symbolsTag.getElementsByTagName(ModelDataAdapter.SYMBOL);
            // go through each symbol
            for (int j = 0; j < symbolList.getLength(); j++){
                Element symbolTag = (Element) symbolList.item(j);
                // symbol name, file, count
                for (int k = 0; k < symbolAttrs.length; k++){
                    String attr = symbolTag.getAttribute(symbolAttrs[k]);
                    valueList.get(i).add(attr);
                }

                NodeList sampleList = symbolsTag.getElementsByTagName(ModelDataAdapter.SAMPLE);
                // go through each sample
                for (int k = 0; k < sampleList.getLength(); k++){
                    Element sampleTag = (Element) sampleList.item(k);

                    for (int n = 0; n < sampleTags.length; n++){
                        Element elem = (Element) sampleTag.getElementsByTagName(sampleTags[n]).item(0);
                        valueList.get(i).add(elem.getTextContent());
                    }
                }
            }
        }
        assertSameValues(valueList);
    }

    private void assertSameValues(ArrayList<ArrayList<String>> valueList) {
        for (int i = 0; i < valueList.get(0).size(); i++){
            assertEquals(valueList.get(0).get(i), valueList.get(1).get(i));
        }
    }
}
