"""
Run a small experiment applying RLS to one 2d bin packing instance.

We plug the second variant (`ImprovedBottomLeftEncoding2`) of the
improved-bottom-left encoding into a simple randomized local search (RLS).
The encoding processes a signed permutation from the beginning to the end and
places objects iteratively into bins. For each object, it will always try all
bins.

We apply the algorithm to instance `a10`. The result of a short run with 1024
steps of the algorithm is a packing that needs two bins only. You can compare
this with the example file `binpacking2d_plot.py`, where three bins are needed
by the same encoding (or four by `ImprovedBottomLeftEncoding1`).
"""
from time import sleep
from webbrowser import open_new_tab

from moptipy.algorithms.so.rls import RLS
from moptipy.api.execution import Execution
from moptipy.operators.signed_permutations.op0_shuffle_and_flip import (
    Op0ShuffleAndFlip,
)
from moptipy.operators.signed_permutations.op1_swap_2_or_flip import (
    Op1Swap2OrFlip,
)
from moptipy.spaces.signed_permutations import SignedPermutations
from moptipy.utils.plot_utils import save_figure
from pycommons.io.temp import temp_dir
from pycommons.processes.caller import is_build

from moptipyapps.binpacking2d.encodings.ibl_encoding_2 import (
    ImprovedBottomLeftEncoding2,
)
from moptipyapps.binpacking2d.instance import Instance
from moptipyapps.binpacking2d.objectives.bin_count_and_last_empty import (
    BinCountAndLastEmpty,
)
from moptipyapps.binpacking2d.packing_space import PackingSpace
from moptipyapps.binpacking2d.plot_packing import plot_packing

# load the problem instance
instance = Instance.from_resource("a10")  # pick instance a10

search_space = SignedPermutations(
    instance.get_standard_item_sequence())  # Create the search space.
solution_space = PackingSpace(instance)  # Create the space of packings.
y = solution_space.create()  # Here we will put the best solution.

# Build a single execution of a single run of a single algorithm, execute it,
# and store the best solution discovered in y.
with Execution()\
        .set_rand_seed(1)\
        .set_search_space(search_space)\
        .set_solution_space(solution_space)\
        .set_encoding(ImprovedBottomLeftEncoding2(instance))\
        .set_algorithm(  # This is the algorithm: Randomized Local Search.
            RLS(Op0ShuffleAndFlip(search_space), Op1Swap2OrFlip()))\
        .set_objective(BinCountAndLastEmpty(instance))\
        .set_max_fes(1024)\
        .execute() as process:
    process.get_copy_of_best_y(y)

# We can now plot the best packing. We create the figures in a temp directory.
# To keep the figures, you would put an existing directory path into `td` by
# doing `from pycommons.io.path import Path; td = Path("mydir")` and not use
# the `with` block.
with temp_dir() as td:  # create temporary directory `td`
    files = []  # the collection of files

# Plot the packing. The default plotting includes the item ID into each
# rectangle. If enough space is there, it will also include the index of the
# item in the bin (starting at 1), and, if then there is still enough space,
# also the overall index of the item in the encoding (starting at 1).
    fig = plot_packing(y, max_bins_per_row=2, max_rows=2)

    # Save the image as svg and png.
    files.extend(save_figure(
        fig=fig,  # store fig to a file
        file_name="packing_plot_a10",  # base name
        dir_name=td,  # store graphic in temp directory
        formats=("svg", "png")))  # file types: svg and png
    del fig  # dispose figure

# OK, we have now generated and saved the plot in a file.
# We will open it in the web browser if we are not in a make build.
    if not is_build():
        for file in files:  # for each file we generated
            open_new_tab(f"file://{file}")  # open a browser tab
        sleep(10)  # sleep 10 seconds (enough time for the browser to load)
# The temp directory is deleted as soon as we leave the `with` block.
# Hence, all the figures generated above as well as the experimental results
# now have disappeared.