//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   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 de.ugoe.cs.autoquest.htmlmonitor;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;

/**
 * <p>
 * TODO comment
 * </p>
 * 
 * @author Patrick Harms
 */
class HtmlGUIElementManager {

    /** */
    private Map<String, HtmlGUIElement> idMap = new HashMap<String, HtmlGUIElement>();
    
    /** */
    private Map<String, List<HtmlPageElement>> domPathMap =
          new HashMap<String, List<HtmlPageElement>>();
    
    /**
     * <p>
     * TODO: comment
     * </p>
     *
     */
    HtmlServer createHtmlServer(String name, int port) {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }
        
        String id = calculateId(name, Integer.toString(port));
        
        HtmlGUIElement server = idMap.get(id);
        
        if (server == null) {
            server = new HtmlServer(id, name, port);
            idMap.put(id, server);
        }
        else if (!(server instanceof HtmlServer)) {
            throw new RuntimeException
                ("id conflict: calculated the same id for two different GUI elements");
        }
        
        return (HtmlServer) server;
    }
    
    /**
     * <p>
     * TODO: comment
     * </p>
     *
     */
    HtmlDocument createHtmlDocument(HtmlServer server, String path, String query, String title) {
        if (server == null) {
            throw new IllegalArgumentException("server must not be null");
        }
        if (path == null) {
            throw new IllegalArgumentException("path must not be null");
        }

        String id = calculateId(server.getId(), path, query, title);
        
        HtmlGUIElement document = idMap.get(id);

        if (document == null) {
            document = new HtmlDocument(id, server, path, query, title);
            idMap.put(id, document);
        }
        else if (!(document instanceof HtmlDocument)) {
            throw new RuntimeException
                ("id conflict: calculated the same id for two different GUI elements");
        }
        
        return (HtmlDocument) document;
    }

    /**
     * <p>
     * TODO: comment
     * </p>
     *
     * @param document
     * @param parent
     * @param tagName
     * @param htmlid
     * @param index
     * @return
     */
    HtmlPageElement createHtmlPageElement(HtmlDocument    document,
                                          HtmlPageElement parent,
                                          String          tagName,
                                          String          htmlId,
                                          Integer         index)
    {
        if (document == null) {
            throw new IllegalArgumentException("document must not be null");
        }
        if (tagName == null) {
            throw new IllegalArgumentException("document must not be null");
        }

        String id = calculateId
            (document.getId(), parent != null ? parent.getDOMPath() : null, tagName, htmlId,
             index != null ? index.toString() : "-1");

        HtmlGUIElement pageElement = idMap.get(id);

        if (pageElement == null) {
            pageElement = new HtmlPageElement(id, document, parent, tagName, htmlId, index);
            idMap.put(id, pageElement);
        }
        else if (!(pageElement instanceof HtmlPageElement)) {
            throw new RuntimeException
                ("id conflict: calculated the same id for two different GUI elements");
        }
            
        List<HtmlPageElement> candidates =
            domPathMap.get(((HtmlPageElement) pageElement).getDOMPath());
        
        if (candidates == null) {
            candidates = new LinkedList<HtmlPageElement>();
            domPathMap.put(((HtmlPageElement) pageElement).getDOMPath(), candidates);
        }
        
        if (!candidates.contains(pageElement)) {
            candidates.add((HtmlPageElement) pageElement);
        }

        return (HtmlPageElement) pageElement;
    }

    /**
     * <p>
     * TODO: comment
     * </p>
     *
     * @param document
     * @param domPath
     * @return
     */
    HtmlPageElement getPageElement(HtmlDocument document, String domPath) {
        List<HtmlPageElement> candidates = domPathMap.get(domPath);
        
        if (candidates != null) {
            for (HtmlPageElement candidate : candidates) {
                if (document.equals(candidate.getDocument())) {
                    return candidate;
                }
            }
        }
        
        return null;
    }

    /**
     * <p>
     * TODO: comment
     * </p>
     *
     * @param name
     * @param string
     * @return
     */
    private String calculateId(String... fragments) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            
            for (String fragment : fragments) {
                if (fragment != null) {
                    md.update(fragment.getBytes());
                }
            }
            
            return Base64.encodeBase64String(md.digest());
        }
        catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("Java VM does not support this code");
        }
    }

}
