/*
 * Copyright 2002,2004 The Apache Software Foundation.
 * 
 * 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 org.apache.axis.tools.ant.wsdl;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectComponent;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;

/**
 * Used for nested package definitions.
 * The file format used for storing mappings is a list of package=namespace
 */
public class NamespaceMapping implements Mapper {


    private String namespace = null;
    private String packageName = null;
    private File mappingFile;

    /**
     * pass in the namespace to map to
     */
    public NamespaceMapping() {
    }

    /**
     * the namespace in the WSDL. Required.
     * @param value new uri of the mapping
     */
    public void setNamespace(String value) {
        namespace = value;
    }

    /**
     * the Java package to bind to. Required.
     * @param value java package name
     */
    public void setPackage(String value) {
        packageName = value;
    }

    /**
     * name of a property file that contains mappings in
     * package=namespace format
     * @param file file to load
     */
    public void setFile(File file) {
        mappingFile = file;
    }

    /**
     * map a namespace to a package
     * @param owner owning project component (For logging)
     * @param map map to assign to
     * @param packName package name
     * @param nspace namespace
     * @param packageIsKey if the package is to be the key for the map
     */
    protected void map(ProjectComponent owner,
                       HashMap map,
                       String packName,
                       String nspace,
                       boolean packageIsKey) {
        owner.log("mapping "+nspace+" to "+packName, Project.MSG_VERBOSE);
        if(packageIsKey) {
            map.put(packName,nspace);
        } else {
            map.put(nspace, packName);
        }
    }

    /**
     * validate the option set
     */
    private void validate() {
        if (mappingFile != null) {
            if (namespace != null || packageName != null) {
                throw new BuildException(
                        "Namespace or Package cannot be used with a File attribute");
            }
        } else {
            if (namespace == null) {
                throw new BuildException("namespace must be defined");
            }
            if (packageName == null) {
                throw new BuildException("package must be defined");
            }
        }
    }

    /**
     * Load a mapping file and save it to the map
     * @param owner owner component
     * @param map target map file
     * @param packageIsKey if the package is to be the key for the map
     * @throws BuildException if an IOException needed swallowing
     */
    protected void mapFile(ProjectComponent owner, HashMap map, boolean packageIsKey) throws BuildException {
        Properties props = loadMappingPropertiesFile();
        Enumeration keys = props.keys();
        while (keys.hasMoreElements()) {
            String packageName = (String) keys.nextElement();
            String namespace = props.getProperty(packageName);
            map(owner, map, packageName, namespace, packageIsKey);
        }
    }

    /**
     * load a file containing properties
     * @return a properties file with zero or more mappings
     * @throws BuildException if the load failed
     */
    private Properties loadMappingPropertiesFile() throws BuildException {
        Properties props = new Properties();
        FileInputStream instr = null;
        try {
            instr = new FileInputStream(mappingFile);
            props.load(new BufferedInputStream(instr));
        } catch (IOException e) {
            throw new BuildException("Failed to load " + mappingFile, e);
        } finally {
            if (instr != null) {
                try {
                    instr.close();
                } catch (IOException e) {
                }
            }
        }
        return props;
    }


    /**
     * execute the mapping
     * @param owner owner object
     * @param map map to map to
     * @param packageIsKey if the package is to be the key for the map
     * @throws BuildException in case of emergency
     */
    public void execute(ProjectComponent owner, HashMap map, boolean packageIsKey) throws BuildException {
        validate();
        if (mappingFile != null) {
            mapFile(owner, map,packageIsKey);
        } else {
            map(owner, map, packageName, namespace, packageIsKey);
        }
    }


}