/*
 * Copyright (c) Contributors, http://opensimulator.org/
 * See CONTRIBUTORS.TXT for a full list of copyright holders.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSim Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.IO;
using System.Reflection;
using libsecondlife;
using log4net;

namespace OpenSim.Framework
{
    public class RegionSettings
    {
        private ConfigurationMember configMember;

        public delegate void SaveDelegate(RegionSettings rs);

        public event SaveDelegate OnSave;

        public RegionSettings()
        {
            if (configMember == null)
            {
                configMember = new ConfigurationMember(Path.Combine(Util.configDir(), "estate_settings.xml"), "ESTATE SETTINGS", LoadConfigurationOptions, HandleIncomingConfiguration, true);
                configMember.performConfigurationRetrieve();
            }
        }

        public void LoadConfigurationOptions()
        {
             configMember.addConfigurationOption("region_flags",
                     ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
                     String.Empty, "336723974", true);

             configMember.addConfigurationOption("max_agents",
                     ConfigurationOption.ConfigurationTypes.TYPE_INT32,
                     String.Empty, "40", true);

             configMember.addConfigurationOption("object_bonus_factor",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "1.0", true);

             configMember.addConfigurationOption("sim_access",
                     ConfigurationOption.ConfigurationTypes.TYPE_INT32,
                     String.Empty, "21", true);

             configMember.addConfigurationOption("terrain_detail_0",
                     ConfigurationOption.ConfigurationTypes.TYPE_LLUUID,
                     String.Empty, "00000000-0000-0000-0000-000000000000",true);

             configMember.addConfigurationOption("terrain_detail_1",
                     ConfigurationOption.ConfigurationTypes.TYPE_LLUUID,
                     String.Empty, "00000000-0000-0000-0000-000000000000",true);

             configMember.addConfigurationOption("terrain_detail_2",
                     ConfigurationOption.ConfigurationTypes.TYPE_LLUUID,
                     String.Empty, "00000000-0000-0000-0000-000000000000",true);

             configMember.addConfigurationOption("terrain_detail_3",
                     ConfigurationOption.ConfigurationTypes.TYPE_LLUUID,
                     String.Empty, "00000000-0000-0000-0000-000000000000",true);

             configMember.addConfigurationOption("terrain_start_height_0",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "10.0", true);

             configMember.addConfigurationOption("terrain_start_height_1",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "10.0", true);

             configMember.addConfigurationOption("terrain_start_height_2",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "10.0", true);

             configMember.addConfigurationOption("terrain_start_height_3",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "10.0", true);

             configMember.addConfigurationOption("terrain_height_range_0",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "60.0", true);

             configMember.addConfigurationOption("terrain_height_range_1",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "60.0", true);

             configMember.addConfigurationOption("terrain_height_range_2",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "60.0", true);

             configMember.addConfigurationOption("terrain_height_range_3",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "60.0", true);

             configMember.addConfigurationOption("region_water_height",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "20.0", true);

             configMember.addConfigurationOption("terrain_raise_limit",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "100.0", true);

             configMember.addConfigurationOption("terrain_lower_limit",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "100.0", true);

             configMember.addConfigurationOption("sun_hour",
                     ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE,
                     String.Empty, "0.0", true);
        }

        public bool HandleIncomingConfiguration(string key, object value)
        {
            switch(key)
            {
            case "region_flags":
                Simulator.RegionFlags flags = (Simulator.RegionFlags)(uint)value;
                
                m_BlockTerraform =
                        (flags & Simulator.RegionFlags.BlockTerraform) != 0;
                m_BlockFly =
                        (flags & Simulator.RegionFlags.NoFly) != 0;
                m_AllowDamage =
                        (flags & Simulator.RegionFlags.AllowDamage) != 0;
                m_RestrictPushing =
                        (flags & Simulator.RegionFlags.RestrictPushObject) != 0;
                m_AllowLandResell =
                        (flags & Simulator.RegionFlags.BlockLandResell) == 0;
                m_AllowLandJoinDivide =
                        (flags & Simulator.RegionFlags.AllowParcelChanges) != 0;
                m_BlockShowInSearch =
                        ((uint)flags & (1 << 29)) != 0;
                m_DisableScripts =
                        (flags & Simulator.RegionFlags.SkipScripts) != 0;
                m_DisableCollisions =
                        (flags & Simulator.RegionFlags.SkipCollisions) != 0;
                m_DisablePhysics =
                        (flags & Simulator.RegionFlags.SkipPhysics) != 0;
                m_FixedSun =
                        (flags & Simulator.RegionFlags.SunFixed) != 0;
                break;
            case "max_agents":
                m_AgentLimit = (int)value;
                break;
            case "object_bonus_factor":
                m_ObjectBonus = (double)value;
                break;
            case "sim_access":
                int access = (int)value;
                if(access <= 13)
                    m_Maturity = 0;
                else
                    m_Maturity = 1;
                break;
            case "terrain_detail_0":
                m_TerrainTexture1 = (LLUUID)value;
                break;
            case "terrain_detail_1":
                m_TerrainTexture1 = (LLUUID)value;
                break;
            case "terrain_detail_2":
                m_TerrainTexture1 = (LLUUID)value;
                break;
            case "terrain_detail_3":
                m_TerrainTexture1 = (LLUUID)value;
                break;
            case "terrain_start_height_0":
                m_Elevation1SW = (double)value;
                break;
            case "terrain_start_height_1":
                m_Elevation1NW = (double)value;
                break;
            case "terrain_start_height_2":
                m_Elevation1SE = (double)value;
                break;
            case "terrain_start_height_3":
                m_Elevation1NE = (double)value;
                break;
            case "terrain_height_range_0":
                m_Elevation2SW = (double)value;
                break;
            case "terrain_height_range_1":
                m_Elevation2NW = (double)value;
                break;
            case "terrain_height_range_2":
                m_Elevation2SE = (double)value;
                break;
            case "terrain_height_range_3":
                m_Elevation2NE = (double)value;
                break;
            case "region_water_height":
                m_WaterHeight = (double)value;
                break;
            case "terrain_raise_limit":
                m_TerrainRaiseLimit = (double)value;
                break;
            case "terrain_lower_limit":
                m_TerrainLowerLimit = (double)value;
                break;
            case "sun_hour":
                m_SunPosition = (double)value;
                break;
            }

            return true;
        }

        public void Save()
        {
            OnSave(this);
        }

        private LLUUID m_RegionUUID = LLUUID.Zero;

		public LLUUID RegionUUID
		{
			get { return m_RegionUUID; }
			set { m_RegionUUID = value; }
		}

        private bool m_BlockTerraform = false;
		
		public bool BlockTerraform
		{
			get { return m_BlockTerraform; }
			set { m_BlockTerraform = value; }
		}

        private bool m_BlockFly = false;
		
		public bool BlockFly
		{
			get { return m_BlockFly; }
			set { m_BlockFly = value; }
		}

        private bool m_AllowDamage = false;
		
		public bool AllowDamage
		{
			get { return m_AllowDamage; }
			set { m_AllowDamage = value; }
		}

        private bool m_RestrictPushing = false;
		
		public bool RestrictPushing
		{
			get { return m_RestrictPushing; }
			set { m_RestrictPushing = value; }
		}

        private bool m_AllowLandResell = true;
		
		public bool AllowLandResell
		{
			get { return m_AllowLandResell; }
			set { m_AllowLandResell = value; }
		}

        private bool m_AllowLandJoinDivide = true;
		
		public bool AllowLandJoinDivide
		{
			get { return m_AllowLandJoinDivide; }
			set { m_AllowLandJoinDivide = value; }
		}

        private bool m_BlockShowInSearch = false;
		
		public bool BlockShowInSearch
		{
			get { return m_BlockShowInSearch; }
			set { m_BlockShowInSearch = value; }
		}

        private int m_AgentLimit = 40;
		
		public int AgentLimit
		{
			get { return m_AgentLimit; }
			set { m_AgentLimit = value; }
		}

        private double m_ObjectBonus = 1.0;
		
		public double ObjectBonus
		{
			get { return m_ObjectBonus; }
			set { m_ObjectBonus = value; }
		}

        private int m_Maturity = 1;
		
		public int Maturity
		{
			get { return m_Maturity; }
			set { m_Maturity = value; }
		}

        private bool m_DisableScripts = false;
		
		public bool DisableScripts
		{
			get { return m_DisableScripts; }
			set { m_DisableScripts = value; }
		}

        private bool m_DisableCollisions = false;
		
		public bool DisableCollisions
		{
			get { return m_DisableCollisions; }
			set { m_DisableCollisions = value; }
		}

        private bool m_DisablePhysics = false;
		
		public bool DisablePhysics
		{
			get { return m_DisablePhysics; }
			set { m_DisablePhysics = value; }
		}

        private LLUUID m_TerrainTexture1 = LLUUID.Zero;
		
		public LLUUID TerrainTexture1
		{
			get { return m_TerrainTexture1; }
			set { m_TerrainTexture1 = value; }
		}

        private LLUUID m_TerrainTexture2 = LLUUID.Zero;
		
		public LLUUID TerrainTexture2
		{
			get { return m_TerrainTexture2; }
			set { m_TerrainTexture2 = value; }
		}

        private LLUUID m_TerrainTexture3 = LLUUID.Zero;
		
		public LLUUID TerrainTexture3
		{
			get { return m_TerrainTexture3; }
			set { m_TerrainTexture3 = value; }
		}

        private LLUUID m_TerrainTexture4 = LLUUID.Zero;
		
		public LLUUID TerrainTexture4
		{
			get { return m_TerrainTexture4; }
			set { m_TerrainTexture4 = value; }
		}

        private double m_Elevation1NW = 10;
		
		public double Elevation1NW
		{
			get { return m_Elevation1NW; }
			set { m_Elevation1NW = value; }
		}

        private double m_Elevation2NW = 60;
		
		public double Elevation2NW
		{
			get { return m_Elevation2NW; }
			set { m_Elevation2NW = value; }
		}

        private double m_Elevation1NE = 10;
		
		public double Elevation1NE
		{
			get { return m_Elevation1NE; }
			set { m_Elevation1NE = value; }
		}

        private double m_Elevation2NE = 60;
		
		public double Elevation2NE
		{
			get { return m_Elevation2NE; }
			set { m_Elevation2NE = value; }
		}

        private double m_Elevation1SE = 10;
		
		public double Elevation1SE
		{
			get { return m_Elevation1SE; }
			set { m_Elevation1SE = value; }
		}

        private double m_Elevation2SE = 60;
		
		public double Elevation2SE
		{
			get { return m_Elevation2SE; }
			set { m_Elevation2SE = value; }
		}

        private double m_Elevation1SW = 10;
		
		public double Elevation1SW
		{
			get { return m_Elevation1SW; }
			set { m_Elevation1SW = value; }
		}

        private double m_Elevation2SW = 60;
		
		public double Elevation2SW
		{
			get { return m_Elevation2SW; }
			set { m_Elevation2SW = value; }
		}

        private double m_WaterHeight = 20;
		
		public double WaterHeight
		{
			get { return m_WaterHeight; }
			set { m_WaterHeight = value; }
		}

        private double m_TerrainRaiseLimit = 100;
		
		public double TerrainRaiseLimit
		{
			get { return m_TerrainRaiseLimit; }
			set { m_TerrainRaiseLimit = value; }
		}

        private double m_TerrainLowerLimit = 100;
		
		public double TerrainLowerLimit
		{
			get { return m_TerrainLowerLimit; }
			set { m_TerrainLowerLimit = value; }
		}

        private bool m_UseEstateSun = true;
		
		public bool UseEstateSun
		{
			get { return m_UseEstateSun; }
			set { m_UseEstateSun = value; }
		}

        private bool m_FixedSun = false;
		
		public bool FixedSun
		{
			get { return m_FixedSun; }
			set { m_FixedSun = value; }
		}

        private double m_SunPosition = 0.0;
		
		public double SunPosition
		{
			get { return m_SunPosition; }
			set { m_SunPosition = value; }
		}

        private LLUUID m_Covenant = LLUUID.Zero;
		
		public LLUUID Covenant
		{
			get { return m_Covenant; }
			set { m_Covenant = value; }
		}
	}
}