/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.xml;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.xml.transform.TransformerConfigurationException;
import net.ranides.assira.TestFiles;
import net.ranides.assira.collection.maps.MultiMap;
import static net.ranides.assira.junit.NewAssert.*;
import static net.ranides.assira.xml.XMLElement.$;
import org.junit.Test;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public class XMLQueryTest {
    
    @Test
    public void testRoot() throws IOException {
        XMLElement doc = $(TestFiles.XML_INPUT);
        
        List<String> root = Arrays.asList("info", "info", "params", "#comment", "ccms");
        List<String> body = Arrays.asList("#text", "users", "#text", "data", "#text", "configuration", "#text");
        List<String> items = Arrays.asList("users", "data", "configuration");
        
        assertEquals(root.subList(0, 5), doc.children().names());
        assertEquals(root.subList(0, 3), doc.children(XMLType.PROCESSING).names());
        assertEquals(root.subList(4, 5), doc.children(XMLType.ELEMENT).names());
        assertEquals(" @author Ranides Atterwim <ranides@gmail.com> ", doc.children(XMLType.COMMENT).text());
        
        assertEquals(body, doc.root().children().names());
        assertEquals(items, doc.root().children(XMLType.ELEMENT).names());
        assertEquals(items, doc.normalize().root().children().names());
        
        assertEquals("ccms", doc.root().name());
    }
    
    @Test
    public void testFindStar() throws IOException {
        XMLElement doc = $(TestFiles.XML_INPUT);
        
        assertEquals(41, doc.find("*").size());
        assertEquals(40, doc.root().find("*").size());
        
        assertEquals(27, doc.find("users *").size());
        assertEquals(27, doc.find("users").find("*").size());
        assertEquals(Arrays.asList("login", "password", "name", "mail", "mail"), doc.find("? //user[1]").find("*").names());
    }
    
    @Test
    public void testXPath() throws IOException {
        XMLElement doc = $(TestFiles.XML_INPUT);
        
        List<String> exp1 = Arrays.asList("101", "102", "103", "104", "105");
        List<String> exp2 = Arrays.asList();

        assertEquals(exp1, doc.find("? //users/user/@id").texts());
        assertEquals(exp2, doc.find("? /users/user/@id").texts());
        assertEquals(exp2, doc.find("? users/user/@id").texts());
        assertEquals(exp1, doc.find("? ccms/users/user/@id").texts());
        assertEquals(exp1, doc.find("? /ccms/users/user/@id").texts());
    }
    
    @Test
    public void testCSS() throws IOException {
        XMLElement doc = $(TestFiles.XML_INPUT);
        
        XMLElements css = doc.find("users user[active='true']").attrs("id");

        assertEquals(Arrays.asList("101", "102", "105"), css.texts());
        
        List<Integer> numbers = Arrays.asList(101, 105);
        
        assertEquals(numbers, css.stream(this::$int).filter(v -> 1 == v%2).list());
    }

    private int $int(XMLElement n) throws NumberFormatException {
        return Integer.parseInt(n.content());
    }
    
    @Test
    public void testChildren() throws IOException {
        XMLElement doc = $(TestFiles.XML_INPUT);
        
        assertFalse(doc.children("xxx").matches());
        assertFalse(doc.children("users").matches());
        assertFalse(doc.children(" users").matches());
        assertFalse(doc.children("users user").matches());
        
        assertFalse(doc.root().children("xxx").matches());
        assertTrue(doc.root().children("users").matches());
        assertTrue(doc.root().children(" users").matches());
        assertFalse(doc.root().children("users user").matches());
        
        assertEquals(0, doc.root().children("xxx").size());
        assertEquals(1, doc.root().children("users").size());
        assertEquals(1, doc.root().children(" users").size());
        assertEquals(0, doc.root().children("users user").size());
        
        assertEquals(0, doc.find("xxx").size());
        assertEquals(1, doc.find("users").size());
        assertEquals(1, doc.find(" users").size());
        assertEquals(5, doc.find("users user").size());
    }
        
    
    @Test
    public void testAttrMap() throws IOException {
        XMLElement doc = $(TestFiles.XML_INPUT);
        
        assertTrue(doc.children("xxx").attrs().map().isEmpty());
        assertTrue(doc.find("users item").attrs().map().isEmpty());
        assertTrue(doc.find("users user login").attrs().map().isEmpty());

        MultiMap<String, String> attr = doc.find("users user").attrs().map();
        
        List<String> exp1 = Arrays.asList("101", "102", "103", "104", "105");
        List<String> exp2 = Arrays.asList("5461", "8721", "7542", "1952", "3773");
        List<String> exp3 = Arrays.asList("false","true");
        
        assertEquivalent(exp1, attr.getAll("id"));
        assertEquivalent(exp2, attr.getAll("uid"));
        assertEquivalent(exp3, attr.getAll("active"));
    }
    
    @Test
    public void testAttributes() throws IOException, TransformerConfigurationException {
        XMLElement doc = $(TestFiles.XML_INPUT);
        
        XMLElement attr1 = doc.find("users user").attrs("id").first();
        XMLElement attr2 = doc.find("users user").attrs().first("id");
        
        assertSame(attr1.node(), attr2.node());
        
        assertEquals("id", attr1.name());
        assertEquals("101", attr1.content());
        assertEquals("101", attr1.text());
        assertEquals("101", attr1.get());
        assertEquals("user", attr1.parent().name());
        assertEquals(Arrays.asList(), attr1.attrs().names());
        assertEquivalent(Arrays.asList("login", "password", "name", "mail", "mail"), attr1.parent().children(XMLType.ELEMENT).names());
        assertEquivalent(Arrays.asList("id", "uid", "active", "public"), attr1.parent().attrs().names());
        assertEquals(Arrays.asList("user", "users", "ccms", "#document"), attr1.parents().names());
    }
    
}
