"""!

@brief Examples of usage and demonstration of abilities of oscillatory network
       based on Hodgkin-Huxley model of neuron.

@authors Andrei Novikov (pyclustering@yandex.ru)
@date 2014-2018
@copyright GNU Public License

@cond GNU_PUBLIC_LICENSE
    PyClustering is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    PyClustering is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
@endcond

"""


from pyclustering.nnet.dynamic_visualizer import dynamic_visualizer;

from pyclustering.nnet.hhn import hhn_network, hhn_parameters;


def template_dynamic_hhn(num_osc, steps, time, stimulus = None, params = None, separate = False, ccore_flag = False):
    net = hhn_network(num_osc, stimulus, params, ccore = ccore_flag);

    (t, dyn_peripheral, dyn_central) = net.simulate(steps, time);

    amount_canvases = 1;
    if (isinstance(separate, list)):
        amount_canvases = len(separate) + 2;
    elif (separate is True):
        amount_canvases = len(dyn_peripheral[0]) + 2;
    
    visualizer = dynamic_visualizer(amount_canvases, x_title = "Time", y_title = "V", y_labels = False);
    visualizer.append_dynamics(t, dyn_peripheral, 0, separate);
    visualizer.append_dynamics(t, dyn_central, amount_canvases - 2, True);
    visualizer.show();


def one_oscillator_unstimulated():
    template_dynamic_hhn(1, 750, 100, separate=True, ccore_flag=False);
    template_dynamic_hhn(1, 750, 100, separate=True, ccore_flag=True);


def one_oscillator_stimulated():
    template_dynamic_hhn(1, 750, 100, [25], separate=True, ccore_flag=False);
    template_dynamic_hhn(1, 750, 100, [25], separate=True, ccore_flag=True);


def three_oscillators_stimulated():
    template_dynamic_hhn(3, 750, 100, [25] * 3, separate=True, ccore_flag=False);
    template_dynamic_hhn(3, 750, 100, [25] * 3, separate=True, ccore_flag=True);


def two_sync_ensembles():
    template_dynamic_hhn(4, 400, 200, [25, 25, 50, 50], separate=True, ccore_flag=False);
    template_dynamic_hhn(4, 800, 200, [25, 25, 50, 50], separate=True, ccore_flag=True);


def ten_oscillators_stimulated_desync():
    params = hhn_parameters();
    params.w1 = 0;
    params.w2 = 0;
    params.w3 = 0;

    stumulus = [25, 25, 25, 25, 25, 11, 11, 11, 11, 11];

    template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=False);
    template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=True);


def ten_oscillators_stimulated_sync():
    params = hhn_parameters();
    params.w1 = 0.1;
    params.w2 = 0.0;
    params.w3 = 0;

    stumulus = [25, 25, 25, 25, 25, 27, 27, 27, 27, 27];

    template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=False);
    template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=True);


def ten_oscillators_stimulated_partial_sync():
    params = hhn_parameters();
    params.w1 = 0.1;
    params.w2 = 5.0;
    params.w3 = 0;

    stimulus = [25, 25, 25, 25, 25, 11, 11, 11, 11, 11];
    template_dynamic_hhn(10, 750, 200, stimulus, params, separate=True, ccore_flag=False);
    template_dynamic_hhn(10, 750, 200, stimulus, params, separate=True, ccore_flag=True);
    

def six_oscillators_mix_2_stimulated():
    params = hhn_parameters();
    params.deltah = 400;

    stimulus = [25, 25, 25, 47, 47, 47];
    template_dynamic_hhn(6, 1200, 600, stimulus, params, separate=True, ccore_flag=False);
    template_dynamic_hhn(6, 2400, 600, stimulus, params, separate=True, ccore_flag=True);


def six_oscillators_mix_3_stimulated():
    params = hhn_parameters();
    params.deltah = 400;

    stimulus = [0, 0, 25, 25, 47, 47];
    template_dynamic_hhn(6, 1200, 600, stimulus, params, separate=True, ccore_flag=False);
    template_dynamic_hhn(6, 2400, 600, stimulus, params, separate=True, ccore_flag=True);


def three_sync_ensembles():
    params = hhn_parameters();
    params.deltah = 400;

    stimulus = [25, 26, 25, 25, 26, 45, 46, 45, 44, 45, 65, 65, 65, 64, 66];
    separate = [ [0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14] ];
    num_osc = len(stimulus);
    template_dynamic_hhn(num_osc, 2400, 600, stimulus, params, separate=separate, ccore_flag=True);


def two_ensembles_80_oscillators():
    params = hhn_parameters();
    params.deltah = 650;
    params.w1 = 0.1;
    params.w2 = 9.0;
    params.w3 = 5.0;
    params.threshold = -10;
    
    expected_ensembles = [];
    stimulus = [];
    
    base_stimulus = 10;
    step_stimulus = 10;
    amount_ensebles = 4;
    region_size = 20;
    for i in range(amount_ensebles):
        expected_ensembles += [ [i for i in range(region_size * i, region_size * i + region_size)] ];
        stimulus += [ base_stimulus + step_stimulus * i ] * region_size;
    
    template_dynamic_hhn(len(stimulus), 4000, 1000, stimulus, params, separate=expected_ensembles, ccore_flag=True);


one_oscillator_unstimulated();
one_oscillator_stimulated();
three_oscillators_stimulated();
two_sync_ensembles();
ten_oscillators_stimulated_desync();
ten_oscillators_stimulated_sync();
ten_oscillators_stimulated_partial_sync();
six_oscillators_mix_2_stimulated();
six_oscillators_mix_3_stimulated();
three_sync_ensembles();
two_ensembles_80_oscillators();