import unittest
from math import inf
from mercury.config.smart_grid import EnergyStorageConfig, ConsumerConfig
from mercury.model.smart_grid.consumer.energy_storage import EnergyStorageAndControl
from mercury.msg.smart_grid import EnergyDemand, PowerGeneration


def internal_advance(model):
    for port in model.out_ports:
        port.clear()
    model.lambdaf()
    model.deltint()


def external_advance(model, e):
    for port in model.out_ports:
        port.clear()
    model.deltext(e)
    for port in model.in_ports:
        port.clear()


class DummyDemand(EnergyDemand):
    def __init__(self, consumer_id: str, power_demand: float):
        super().__init__()
        self._consumer_id = consumer_id
        self._power_demand = power_demand

    @property
    def consumer_id(self) -> str:
        return self._consumer_id

    @property
    def power_demand(self) -> float:
        return self._power_demand


class TestEnergyStorageAndControl(unittest.TestCase):
    def test_static(self):
        consumer_id = 'consumer'
        provider_id = 'provider'
        storage_config = EnergyStorageConfig(100, 100, -100, 100)
        manager_id = 'static'
        manager_config = dict()
        consumer_config = ConsumerConfig(consumer_id, provider_id, storage_config, manager_id, manager_config)

        storage = EnergyStorageAndControl(consumer_config)

        # Assert that initial conditions are accomplished
        storage.initialize()
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)

        # Test 1: Battery receives new Power Generation Reports without having received an EDC report
        storage.input_pwr_generation.add(PowerGeneration(consumer_id, 'wind', 0))
        storage.input_pwr_generation.add(PowerGeneration(consumer_id, 'solar', 0))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertFalse(storage.output_energy_consumption)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)

        # Test 2: Battery receives first consumer
        storage.input_energy_demand.add(DummyDemand(consumer_id, 0))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertTrue(storage.output_energy_consumption)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)

        # Test 3: wind energy starts to produce 50 Watts
        storage.input_pwr_generation.add(PowerGeneration(consumer_id, 'wind', 50))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 0)
        self.assertEqual(msg.power_generation, 50)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.energy_stored, storage.capacity)
        self.assertEqual(msg.power_consumption, -50)

        # Test 4: EDC starts to demand 50 watts
        storage.input_energy_demand.add(DummyDemand(consumer_id, 50))
        external_advance(storage, 10)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 50)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 50)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 50)
        self.assertEqual(msg.power_generation, 50)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, storage.capacity)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 5: EDC starts to demand 100 watts (but battery discharge is disabled)
        storage.input_energy_demand.add(DummyDemand(consumer_id, 100))
        external_advance(storage, 10)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 100)
        self.assertEqual(msg.power_generation, 50)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, storage.capacity)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 50)

        # Test 6: Battery discharge is enabled
        storage.manager.allow_discharge = True
        storage.input_energy_demand.add(DummyDemand(consumer_id, 100))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, -50)
        self.assertEqual(storage.eventual_rate, -50)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, -50)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 50)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 7200)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 100)
        self.assertEqual(msg.power_generation, 50)
        self.assertEqual(msg.power_storage, -50)
        self.assertEqual(msg.energy_stored, storage.capacity)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 7: wind energy stops producing energy
        storage.input_pwr_generation.add(PowerGeneration(consumer_id, 'wind', 0))
        external_advance(storage, 3600)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, -100)
        self.assertEqual(storage.eventual_rate, -100)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, -100)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 1800)  # half an hour
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 100)
        self.assertEqual(msg.power_generation, 0)
        self.assertEqual(msg.power_storage, -100)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 8: battery runs out of energy
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 0)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)  # half an hour
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 100)
        self.assertEqual(msg.power_generation, 0)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, 0)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 100)

        # Test 9: wind and solar energy starts producing 50 Watts each
        storage.input_pwr_generation.add(PowerGeneration(consumer_id, 'wind', 50))
        storage.input_pwr_generation.add(PowerGeneration(consumer_id, 'solar', 50))
        external_advance(storage, 80)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 100)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, 0)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 10: EDC starts to demand 50 watts
        storage.input_energy_demand.add(DummyDemand(consumer_id, 50))
        external_advance(storage, 100)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, 50)
        self.assertEqual(storage.eventual_rate, 50)
        self.assertEqual(storage.power_demand, 50)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 50)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 50)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 7200)  # 2 hours
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 50)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 50)
        self.assertEqual(msg.energy_stored, 0)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 11: EDC starts to demand 150 watts
        storage.input_energy_demand.add(DummyDemand(consumer_id, 150))
        external_advance(storage, 3600)  # 1 hour
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, -50)
        self.assertEqual(storage.eventual_rate, -50)
        self.assertEqual(storage.power_demand, 150)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, -50)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 150)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 3600)  # 1 hour
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 150)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, -50)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 12: EDC starts to demand 100 watts
        storage.input_energy_demand.add(DummyDemand(consumer_id, 100))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)

        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 100)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 13: Charge from grid enabled
        storage.manager.allow_charge = True
        storage.input_energy_demand.add(DummyDemand(consumer_id, 100))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, 100)
        self.assertEqual(storage.eventual_rate, 100)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 100)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 100)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 1800)  # half an hour
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 100)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 100)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 100)

        # Test 14: EDC starts to demand 200 watts
        storage.input_energy_demand.add(DummyDemand(consumer_id, 200))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, 100)
        self.assertEqual(storage.eventual_rate, 100)
        self.assertEqual(storage.power_demand, 200)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 100)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 200)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 1800)  # Half an hour
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 200)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 100)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 200)

        # Test 15: everything disabled
        storage.manager.allow_charge = False
        storage.manager.allow_discharge = False
        storage.input_energy_demand.add(DummyDemand(consumer_id, 200))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 200)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 200)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 200)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 100)

        # Test 16: Discharge is enabled
        storage.manager.allow_discharge = True
        storage.input_energy_demand.add(DummyDemand(consumer_id, 200))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, -100)
        self.assertEqual(storage.eventual_rate, -100)
        self.assertEqual(storage.power_demand, 200)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, -100)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 200)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_DISCHARGING)
        self.assertEqual(storage.sigma, 1800)  # half an hour
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 200)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, -100)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 17: Battery discharges
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 200)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 200)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, 0)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 100)

        # Test 18: EDC starts to demand 50 watts
        storage.input_energy_demand.add(DummyDemand(consumer_id, 50))
        external_advance(storage, 0)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, 0)
        self.assertEqual(storage.actual_rate, 50)
        self.assertEqual(storage.eventual_rate, 50)
        self.assertEqual(storage.power_demand, 50)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, 0)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 50)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 50)
        self.assertEqual(storage.power_generation, 100)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 7200)  # 2 hours
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 50)
        self.assertEqual(msg.power_generation, 100)
        self.assertEqual(msg.power_storage, 50)
        self.assertEqual(msg.energy_stored, 0)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, 0)

        # Test 19: EDC starts to demand 0 watts, new source of energy gives 50 Watts extra
        storage.input_energy_demand.add(DummyDemand(consumer_id, 0))
        storage.input_pwr_generation.add(PowerGeneration(consumer_id, 'waves', 50))
        external_advance(storage, 3600)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity / 2)
        self.assertEqual(storage.actual_rate, 100)
        self.assertEqual(storage.eventual_rate, 100)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 150)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 0)
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity / 2)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 100)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 150)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_CHARGING)
        self.assertEqual(storage.sigma, 1800)  # half an hour
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 0)
        self.assertEqual(msg.power_generation, 150)
        self.assertEqual(msg.power_storage, 100)
        self.assertEqual(msg.energy_stored, storage.capacity / 2)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, -50)

        # Test 20: Battery charges
        internal_advance(storage)
        self.assertEqual(storage.actual_charge, storage.capacity)
        self.assertEqual(storage.eventual_charge, storage.capacity)
        self.assertEqual(storage.actual_rate, 0)
        self.assertEqual(storage.eventual_rate, 0)
        self.assertEqual(storage.power_demand, 0)
        self.assertEqual(storage.power_generation, 150)
        self.assertEqual(storage.phase, EnergyStorageAndControl.PHASE_PASSIVE)
        self.assertEqual(storage.sigma, inf)
        msg = storage.output_energy_consumption.get()
        self.assertEqual(msg.consumer_id, consumer_id)
        self.assertEqual(msg.power_demand, 0)
        self.assertEqual(msg.power_generation, 150)
        self.assertEqual(msg.power_storage, 0)
        self.assertEqual(msg.energy_stored, storage.capacity)
        self.assertEqual(msg.energy_capacity, storage.capacity)
        self.assertEqual(msg.power_consumption, -150)
