'''
:copyright: (c) 2021, Alliance for Sustainable Energy, LLC
:license: BSD-3
'''
from __future__ import print_function, division, absolute_import
import json
import subprocess
import sys
import pytest
from layerstack import ArgMode, LayerStackRuntimeError
from layerstack.layer import Layer, LayerBase, ModelLayerBase
from layerstack.tests import layer_library_dir, outdir
from layerstack.tests.test_session import manage_outdir
created_layers_library_dir = outdir / 'test_layer_creation'
[docs]class ModelForTests(object):
    def __init__(self, name, count=0, data = []):
        self.name = name
        self.count = count
        self.data = data
[docs]    def save(self, filename):
        with open(filename, 'w') as f:
            json.dump({'name': self.name, 
                       'count': self.count,
                       'data': self.data}, f, indent=4) 
[docs]    @classmethod
    def load(cls, filename):
        json_data = json.load(filename)
        return ModelForTests(json_data['name'],
                             count = json_data['count'],
                             data = json_data['data'])  
[docs]class LayerBaseClassForTestsWithModels(ModelLayerBase):
    @classmethod
    def _check_model_type(cls, model):
        assert isinstance(model, ModelForTests)
    
    @classmethod
    def _load_model(cls, model_path):
        return ModelForTests.load(model_path)
    @classmethod
    def _save_model(cls, model, model_path):
        model.save(model_path) 
[docs]@pytest.fixture(scope='module',autouse=True)
def create_layer_library_dir(manage_outdir):
    assert outdir.exists(), outdir
    assert not created_layers_library_dir.exists()
    created_layers_library_dir.mkdir() 
[docs]def test_layer_base():
    _layer_dir = Layer.create('Test Layer Base', created_layers_library_dir)
    # should be able to run the layer as-is
    subprocess.check_call([
        sys.executable, 
        str(created_layers_library_dir / 'test_layer_base' / 'layer.py'), 
        'dummy_arg']) 
[docs]def test_model_dependent_args_kwargs():
    # without model
    layer = Layer(layer_library_dir / 'test_model_dependent_args_kwargs')
    assert not layer.args[1].is_list, layer.args[1]
    assert layer.kwargs['data_element'].choices is None, layer.kwargs['data_element']
    layer.set_arg_mode(ArgMode.USE)
    layer.args[0] = 'hello'
    layer.args[1] = 1
    layer.kwargs['data_element'] = 'anything allowed'
    assert layer.runnable
    # a model with no data
    model = ModelForTests('Gilbert', count = 2)
    layer = Layer(layer_library_dir / 'test_model_dependent_args_kwargs', model = model)
    assert layer.args[1].is_list, layer.args[1]
    assert layer.args[1].nargs == 2, layer.args[1]
    assert layer.kwargs['data_element'].choices is None, layer.kwargs['data_element']
    layer.set_arg_mode(ArgMode.USE)
    layer.args[0] = model.name
    with pytest.raises(Exception):
        layer.args[1] = 1
    layer.kwargs['data_element'] = 'anything allowed'
    assert not layer.runnable
    layer.args[1] = [3, 4]
    assert layer.runnable
    # a model with data
    model = ModelForTests('Paula', count = 1, data = ['red', 'green', 'purple'])
    layer = Layer(layer_library_dir / 'test_model_dependent_args_kwargs', model = model)
    assert layer.args[1].is_list, layer.args[1]
    assert layer.args[1].nargs == 1, layer.args[1]
    assert len(layer.kwargs['data_element'].choices) == 3, layer.kwargs['data_element']
    assert layer.kwargs['data_element'].default == 'red', layer.kwargs['data_element']
    layer.set_arg_mode(ArgMode.USE)
    layer.args[0] = model.name
    with pytest.raises(Exception):
        layer.args[1] = 1
    assert not layer.runnable
    layer.args[1] = [2]
    assert layer.runnable
    with pytest.raises(LayerStackRuntimeError):
        layer.kwargs['data_element'] = 'anything allowed'
    assert layer.kwargs['data_element'] == 'red', layer.kwargs['data_element']
    layer.kwargs['data_element'] = 'purple'
    assert layer.kwargs['data_element'] == 'purple', layer.kwargs['data_element']