/* Copyright (c) 2005 Stanford University and Christopher Bruns
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * Created on May 16, 2006
 * Original author: Christopher Bruns
 */
package org.simtk.isimsu;

import java.io.IOException;
import java.net.URL;
import java.util.*;
import org.jdom.*;
import org.jdom.input.SAXBuilder;

public class SaltRangeSet extends Vector<SaltConditionRange> {

    // Load precomputed excess chemical potential data for ion conditions
    static public SaltRangeSet loadIonConditions(URL url)
    throws JDOMException, IOException
    {
        SaltRangeSet ionConditionSet = new SaltRangeSet();
        ionConditionSet.addRanges(url);
        return ionConditionSet;
    }
    
    public void addRanges(URL url)
    throws JDOMException, IOException
    {
        SAXBuilder parser = new SAXBuilder();
        parser.setValidation(true);
        org.jdom.Document doc = parser.build(url);
        
        // Parse the document
        // Loop over sets of ion conditions
        java.util.List<Element> conditionsList = doc.getRootElement().getChildren();
        
        for (Element conditionsRangeElement : conditionsList) {
            SaltConditionRange saltConditionRange = new SaltConditionRange();
            
            String surfaceModelName = conditionsRangeElement.getAttributeValue("surface_model");
            if (surfaceModelName.equals("HARD_SPHERE"))
                saltConditionRange.setIonSurfaceModel(IonSpecies.HARD_SPHERE_MODEL);
            else 
                saltConditionRange.setIonSurfaceModel(IonSpecies.LENNARD_JONES_MODEL);

            // Parse Temperature
            Attribute temperature = conditionsRangeElement.getAttribute("temperature");
            saltConditionRange.setTemperature( (new Float(temperature.getValue())).floatValue() );
            
            // Parse solvent permittivity
            Attribute solventPermittivity = conditionsRangeElement.getAttribute("solvent_permittivity");
            saltConditionRange.setSolventPermittivity( (new Float(solventPermittivity.getValue())).floatValue() );
            
            // Loop over ion types in conditions
            Iterator ionSpeciesIterator = conditionsRangeElement.getChildren().iterator();
            
            Map<String, IonSpecies> idIonMap = new HashMap<String, IonSpecies>();

            List<Element> ionsList = conditionsRangeElement.getChildren();            
            for (Element ion : ionsList) {
                // Make sure we are still in ion species, rather than in salt conditions
                if (ion.getName().equals("ion_species")) {                        
                    IonSpecies ionSpecies = new IonSpecies();
                    
                    String ionId = ion.getAttributeValue("ion_id");
                    ionSpecies.setIonId(ionId);
                    ionSpecies.setRadius( (new Float(ion.getAttributeValue("radius"))).floatValue() );
                    ionSpecies.setCharge( (new Float(ion.getAttributeValue("charge"))).floatValue() );    
                        
                    // Store species for later retrieval by the concentration/potential values
                    idIonMap.put(ionId, ionSpecies);
                    
                    // Add ion to condition                    
                    saltConditionRange.addIonSpecies(ionSpecies);
                }

                else if (ion.getName().equals("salt_condition")) {
                    SaltCondition saltCondition = new SaltCondition(saltConditionRange);

                    // Parse name of this set of ion concentrations
                    Attribute description = ion.getAttribute("condition_name");
                    saltCondition.setName(description.getValue());

                    // Parse name and concentrations/potentials
                    List<Element> concentrationList = ion.getChildren();
                    for (Element concentration : concentrationList) {
                        String ionSpeciesId = concentration.getAttributeValue("ion_id");
                        IonSpecies ionSpecies = (IonSpecies) idIonMap.get(ionSpeciesId);
                        
                        IonConcentration ionConcentration = new IonConcentration(ionSpecies, saltCondition);
                        
                        ionConcentration.setConcentration( (new Float(concentration.getAttributeValue("concentration"))).floatValue() );
                        
                        float excessChemicalPotential = (new Float(concentration.getAttributeValue("excess_chemical_potential"))).floatValue();
                        ionConcentration.setExcessChemicalPotential(excessChemicalPotential);
                        // System.out.println("excess potential = "+ionConcentration.getExcessChemicalPotential());
                        
                        saltCondition.addIonConcentration(ionConcentration);
                    }
                        
                    saltConditionRange.addSaltCondition(saltCondition);
                }
                
                else 
                    throw new RuntimeException("Expected salt_condition or ion_species in xml, got " + ion.getName());
            }

            // Add this conditions to global list
            add(saltConditionRange);
        }
    }
}
