import IPython
IPython.__version__

import ultrastorage
ultrastorage.__version__

"""
Explanation: Basic Ultrastorage: Storage system
For reproducibility.
End of explanation
"""


from ultrastorage.storagesystem import StorageSystem
from ultrastorage.item import Item

"""
Explanation: Creating storage systems
A Storage system is a collection of storage units. It is the responsability of the storage system to add items to the various storage units.
End of explanation
"""


storage_system = StorageSystem()
print("storage system={}".format(storage_system))

"""
Explanation: Create a storage system. Without any argument, the storage unit is given a unique name and a transfert rate of 1.
End of explanation
"""


storage_system = StorageSystem(name="myStorageSystem", transfert_rate=0.5)
print("storage system={}".format(storage_system))

"""
Explanation: Initially, the storage unit does not contain any storage unit as shown by $\texttt{storage unit=()}$.
A name and/or a transfert rate may be given.
End of explanation
"""


storage_system = StorageSystem(name="myStorageSystem")

# storage unit specifications 
capacity = 100
cpu = 1
name = "myFirstStorageUnit"

# add the storage unit to the storage system
storage_system.add_storage_unit(capacity, cpu, name)

print("storage system={}".format(storage_system))

storage_system.add_storage_unit(2000, 2)
storage_system.add_storage_unit(3000, 3)

print(storage_system)

"""
Explanation: Adding and removing storage units
Use the 
add_storage_unit(self, capacity, cpu, name=None)

method to add a storage unit to the storage system. The first two arguments are mandatory.
End of explanation
"""


storage_system.remove_storage_unit(name)
print("storage system={}".format(storage_system))

"""
Explanation: Use the
remove_storage_unit(self, storage_unit_name)

method to remove a storage unit.
End of explanation
"""


from ultrastorage.storagesystem import storage_system_builder

capacities = [1000, 2000, 3000]
cpus = [1, 2, 3]
storage_system = storage_system_builder(capacities, cpus)
print("storage system={}".format(storage_system))

"""
Explanation: More on creating a strorage system
The
storage_system_builder(capacities, cpus, name=None, transfert_rate=1., storage_unit_names=None)

function is a convenient function for both creating a storage system and adding storage units at the same time. Storage unitsare defined by giving the capacities and CPUs of the storage units to be added to the newly created storage system.
End of explanation
"""


from ultrastorage.storagesystem import RegularStorageSystem

# a regular storage system hosting storage units of capacity 1000
capacity = 1000
regular_storage_system = RegularStorageSystem(capacity)

# add some storage units
cpus = [1, 2, 3]
for cpu in cpus:
    regular_storage_system.add_storage_unit(cpu)

print("storage system={}".format(regular_storage_system))

from ultrastorage.storagesystem import regular_storage_system_builder

# a regular storage system hosting 3 storage units of capacity 1000 each
capacity = 1000
cpus = [1, 2, 3]
regular_storage_system = regular_storage_system_builder(capacity, cpus)

print("storage system={}".format(regular_storage_system))

"""
Explanation: Some contrained storage systems are defined:

a regular storage system is composed of storage units of the same capacity (by they may differ in the number of CPUs they have),
a semi-homogeneous storage system is composed of storage units with the same number of CPUs (bu they may differ in the capacity they have),
a homegeneous storage system is composed of storage units with the same capacity and the same number of CPUs.

Regular storage systems
End of explanation
"""


from ultrastorage.storagesystem import SemiHomogeneousStorageSystem

# a semi-homogeneous storage system hosting storage units with 2 CPUs
cpus = 2
semi_homogeneous_storage_system = SemiHomogeneousStorageSystem(cpus)

# add some storage units
capacities = [1000, 2000, 3000]
for capacity in capacities:
    semi_homogeneous_storage_system.add_storage_unit(capacity)

print("storage system={}".format(semi_homogeneous_storage_system))

from ultrastorage.storagesystem import semi_homogeneous_storage_system_builder

# a semi-homogeneous storage system hosting 3 storage units with 2 CPUs each
cpu = 2
capacities = [1000, 2000, 3000]
semi_homogeneous_storage_system = semi_homogeneous_storage_system_builder(cpu, capacities)

print("storage system={}".format(semi_homogeneous_storage_system))

"""
Explanation: Semi-homegeneous storage systems
End of explanation
"""


from ultrastorage.storagesystem import HomogeneousStorageSystem

# an homogeneous storage system hosting storage units with 2 CPUs and capacity 1000
capacity = 1000
cpu = 2
homogeneous_storage_system = HomogeneousStorageSystem(capacity, cpu)

# add some storage units
number_of_storage_units = 3
for _ in range(number_of_storage_units):
    homogeneous_storage_system.add_storage_unit()

print("storage system={}".format(homogeneous_storage_system))

from ultrastorage.storagesystem import homogeneous_storage_system_builder

# an homogeneous storage system hosting 3 storage units with capacity 1000 and 2 CPUs
number_of_storage_units = 3
capacity = 1000
cpu = 2
homogeneous_storage_system = homogeneous_storage_system_builder(number_of_storage_units, capacity, cpu)

print("storage system={}".format(homogeneous_storage_system))

"""
Explanation: Homegeneous storage systems
End of explanation
"""


# create a new storage system
storage_system = StorageSystem()

# add one storage unit names "myStorageUnit" to the storage system
capacity = 1000
cpu = 2
name = "myStorageUnit"
storage_system.add_storage_unit(capacity, cpu, name)

print("storage system={}".format(storage_system))

item = Item(400)
storage_system.add_item(name, item)

print("storage system={}".format(storage_system))

"""
Explanation: Adding and deleting items
Add items to the storage system using the
add_item(self, storage_unit_name, item)

method.
End of explanation
"""


