import os
import shap
import torch
import pickle
import PhenPred
import warnings
import numpy as np
import pandas as pd
import torch.nn as nn
import seaborn as sns
import matplotlib.pyplot as plt
from tqdm import tqdm
from torchinfo import summary
from datetime import datetime
from PhenPred.vae import plot_folder
from torch.utils.data import DataLoader
from PhenPred.vae.Model import MOVE
from PhenPred.vae.ModelGMVAE import GMVAE
from PhenPred.vae.Losses import CLinesLosses
from sklearn.model_selection import (
    KFold,
    StratifiedKFold,
    StratifiedShuffleSplit,
    ShuffleSplit,
)

class CLinesTrain:
    def __init__(
        self,
        data,
        hypers,
        stratify_cv_by=None,
        early_stop_patience=20,
        timestamp=None,
        verbose=0,
    ):
        self.data = data
        self.losses = []
        self.hypers = hypers
        self.stratify_cv_by = stratify_cv_by
        self.verbose = verbose

        self.timestamp = (
            datetime.now().strftime("%Y%m%d_%H%M%S") if timestamp is None else timestamp
        )

        self.early_stop_patience = early_stop_patience

        self.lrs = [(1, hypers["learning_rate"])]
        self.benchmark_scores = []

        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    def run(self, run_timestamp=None):
        if run_timestamp is not None:
            self.timestamp = run_timestamp
            return

        if not self.hypers["skip_cv"]:
            self.training(drop_last=True)
            losses_df = self.save_losses()
            self.plot_losses(losses_df)

        self.predictions(drop_last=True)

        if self.hypers["save_model"]:
            self.save_model()

    def initialize_model(self):
        views_sizes = {n: v.sum() for n, v in self.data.features_mask.items()}
        views_sizes_full = None

        if self.hypers["filtered_encoder_only"]:
            views_sizes_full = {n: v.shape[1] for n, v in self.data.views.items()}

        assert self.hypers["model"] in ["MOVE", "GMVAE"], "Invalid model"

        if self.hypers["model"] == "MOVE":
            model = MOVE(
                hypers=self.hypers,
                views_sizes=views_sizes,
                conditional_size=self.data.labels.shape[1]
                if self.hypers["use_conditionals"]
                else 0,
                views_sizes_full=views_sizes_full,
            )
        else:
            model = GMVAE(
                hypers=self.hypers,
                views_sizes=views_sizes,
                views_sizes_full=views_sizes_full,
                conditional_size=self.data.labels.shape[1]
                if self.hypers["use_conditionals"]
                else 0,
            )

        model = nn.DataParallel(model)

        print(summary(model))

        return model

    def epoch(
        self,
        model,
        optimizer,
        dataloader,
        record_losses=None,
    ):
        for data in dataloader:
            x, y, x_nans, x_mask = data

            x = [m.to(self.device) for m in x]
            x_nans = [m.to(self.device) for m in x_nans]

            x_masked = [m[:, x_mask[i][0]].to(self.device) for i, m in enumerate(x)]
            x_nans_masked = [
                m[:, x_mask[i][0]].to(self.device) for i, m in enumerate(x_nans)
            ]

            y = y.to(self.device)

            optimizer.zero_grad()

            with torch.set_grad_enabled(model.training):
                if self.hypers["use_conditionals"]:
                    out_net = model(x_masked + [y])
                else:
                    out_net = model(x_masked)

                if self.hypers["filtered_encoder_only"]:
                    # if filtered_encoder_only, use all data for loss
                    loss = model.module.loss(x, x_nans, out_net, y, x_mask)
                else:
                    # otherwise, use only filtered data for loss
                    loss = model.module.loss(
                        x_masked, x_nans_masked, out_net, y, x_mask
                    )

                if model.training:
                    loss["total"].backward()
                    optimizer.step()

            if record_losses is not None:
                self.register_loss(loss, record_losses)

                if self.verbose > 1:
                    self.benchmarks(x, y, out_net["x_hat"], record_losses)

            else:
                self.print_single_loss(loss)

    def benchmarks(self, x, labels, x_hat, record_losses):
        # CDKN2A proteomics benchmark
        f = "CDKN2A"

        prot_idx = self.data.get_view_feature_index(f, "proteomics")
        prot_view_index = self.data.view_names.index("proteomics")
        prot_pred = x_hat[prot_view_index][:, prot_idx]

        if "copynumber" in self.data.view_names:
            cnvs_idx = self.data.get_view_feature_index(f, "copynumber")
            cnvs_view_index = self.data.view_names.index("copynumber")
            cnvs_true = x[cnvs_view_index][:, cnvs_idx]
        else:
            cnvs_idx = self.data.labels_name.index(f"cnv_{f}")
            cnvs_true = labels[:, cnvs_idx]

        # check if there are any CNVs with -2 value
        f_score = np.nanmedian(
            prot_pred[cnvs_true != -2].detach().numpy()
        ) - np.nanmedian(prot_pred[cnvs_true == -2].detach().numpy())

        f_res = dict(benchmark=f, score=f_score)
        f_res.update(record_losses)
        self.benchmark_scores.append(f_res)

    def cv_strategy(self, shuffle_split=False):
        if shuffle_split and self.stratify_cv_by is not None:
            cv = StratifiedShuffleSplit(
                n_splits=self.hypers["n_folds"],
                test_size=0.1,
                random_state=42,
            ).split(self.data, self.stratify_cv_by.reindex(self.data.samples))
        elif shuffle_split:
            cv = ShuffleSplit(
                n_splits=self.hypers["n_folds"], test_size=0.1, random_state=42
            ).split(self.data)
        elif self.stratify_cv_by is not None:
            cv = StratifiedKFold(
                n_splits=self.hypers["n_folds"], shuffle=True, random_state=42
            ).split(self.data, self.stratify_cv_by.reindex(self.data.samples))
        else:
            cv = KFold(
                n_splits=self.hypers["n_folds"], shuffle=True, random_state=42
            ).split(self.data)

        return cv

    def training(self, cv=None, drop_last=False):
        cv_idx, epoch = 0, 0

        cvtest_datasets = {n: [] for n in self.data.view_names}

        cv = self.cv_strategy() if cv is None else cv

        for cv_idx, (train_idx, test_idx) in enumerate(cv, start=1):
            is_early_stop = False

            # Train and Test Data
            data_train = torch.utils.data.Subset(self.data, train_idx)
            dataloader_train = DataLoader(
                data_train,
                batch_size=self.hypers["batch_size"],
                shuffle=True,
                drop_last=drop_last,
            )

            data_test = torch.utils.data.Subset(self.data, test_idx)
            dataloader_test = DataLoader(
                data_test,
                batch_size=self.hypers["batch_size"],
                shuffle=False,
                drop_last=drop_last,
            )

            # Initialize Model and Optimizer
            model = self.initialize_model()
            optimizer = CLinesLosses.get_optimizer(model, self.hypers)
            scheduler = CLinesLosses.get_scheduler(optimizer, self.hypers)

            model.to(self.device)

            # Train and Test Model
            loss_previous, loss_counter = None, 0
            for epoch in range(1, self.hypers["num_epochs"] + 1):
                # Train
                model.train()
                self.epoch(
                    model,
                    optimizer,
                    dataloader_train,
                    dict(
                        cv=cv_idx,
                        epoch=epoch,
                        type="train",
                        lr=optimizer.param_groups[0]["lr"],
                    ),
                )

                # Test
                model.eval()
                self.epoch(
                    model,
                    optimizer,
                    dataloader_test,
                    dict(
                        cv=cv_idx,
                        epoch=epoch,
                        type="val",
                        lr=optimizer.param_groups[0]["lr"],
                    ),
                )

                if self.hypers["model"] == "GMVAE" and self.hypers["gmvae_decay_temp"]:
                    new_gumbel_temp = np.maximum(
                        self.hypers["gmvae_init_temp"]
                        * np.exp(-self.hypers["gmvae_decay_temp_rate"] * epoch),
                        self.hypers["gmvae_min_temp"],
                    )

                    if self.verbose > 1:
                        print(f"Gumbel Temperature: {new_gumbel_temp:.3f}")

                    model.module.gumbel_temp = new_gumbel_temp

                self.print_losses(cv_idx, epoch)

                # Early Stopping
                loss_current = self.get_losses(cv_idx, epoch, "type").loc[
                    "val", "reconstruction"
                ]
                loss_current_total = self.get_losses(cv_idx, epoch, "type").loc[
                    "val", "total"
                ]

                # Check if loss is finite
                if not (np.isfinite(loss_current) or np.isfinite(loss_current_total)):
                    warnings.warn(f"NaN or Inf loss at cv {cv_idx}, epoch {epoch}.")
                    return np.nan, cvtest_datasets

                elif loss_previous is None:
                    loss_previous = loss_current

                elif round(loss_current, 2) < round(loss_previous, 2):
                    loss_counter = 0
                    loss_previous = loss_current

                else:
                    loss_counter += 1

                if loss_counter >= self.early_stop_patience:
                    warnings.warn(f"Early stopping at cv {cv_idx}, epoch {epoch}.")
                    is_early_stop = True

                if scheduler is not None:
                    self.update_learning_rate(scheduler, optimizer, loss_current, epoch)

                # If last epoch, save test predictions
                if epoch == self.hypers["num_epochs"] or is_early_stop:
                    data_test_all = DataLoader(
                        data_test, batch_size=len(test_idx), shuffle=False
                    )

                    for data in data_test_all:
                        x, y, _, x_mask = data

                        x_masked = [m[:, x_mask[i][0]] for i, m in enumerate(x)]

                        if self.hypers["use_conditionals"]:
                            out_net = model(x_masked + [y])
                        else:
                            out_net = model(x_masked)

                        x_hat = out_net["x_hat"]

                        for name, df in zip(self.data.view_names, x_hat):
                            df_hat = pd.DataFrame(
                                self.data.view_scalers[name].inverse_transform(
                                    df.tolist()
                                ),
                                index=pd.Series(self.data.samples)
                                .iloc[test_idx]
                                .values,
                                columns=self.data.view_feature_names[name],
                            )

                            if name in {"copynumber"}:
                                df_hat = df_hat.round()

                            cvtest_datasets[name].append(df_hat)

                    break

        # Concat test datasets
        cvtest_datasets = {
            name: pd.concat(dfs) for name, dfs in cvtest_datasets.items()
        }

        for name, df in cvtest_datasets.items():
            df.round(5).to_csv(
                f"{plot_folder}/files/{self.timestamp}_imputed_{name}_cvtest.csv.gz",
                compression="gzip",
            )

        return (
            self.get_losses(cv_idx, epoch, "type").loc["val", "reconstruction"],
            cvtest_datasets,
        )

    def update_learning_rate(self, scheduler, optimizer, loss_current, epoch):
        scheduler.step(loss_current)

        current_lr = optimizer.param_groups[0]["lr"]

        if round(current_lr, 4) < round(self.lrs[-1][1], 4):
            self.lrs.append((epoch, current_lr))

    def predictions(self, n_epochs=None, drop_last=False):
        imputed_datasets = dict()

        n_epochs = self.hypers["num_epochs"] if n_epochs is None else n_epochs

        # Data Loader
        data_all = DataLoader(
            self.data,
            batch_size=self.hypers["batch_size"],
            shuffle=True,
            drop_last=drop_last,
        )

        self.model = self.initialize_model()
        optimizer = CLinesLosses.get_optimizer(self.model, self.hypers)

        for e in range(1, n_epochs + 1):
            self.model.train()
            print(f"Epoch {e:03}")
            self.epoch(
                self.model,
                optimizer,
                data_all,
            )

        # Make predictions and latent spaces
        data_all = DataLoader(
            self.data, batch_size=len(self.data.samples), shuffle=False
        )

        self.model.eval()
        with torch.no_grad():
            for data in data_all:
                x, y, _, x_mask = data

                x_masked = [m[:, x_mask[i][0]] for i, m in enumerate(x)]

                if self.hypers["use_conditionals"]:
                    out_net = self.model(x_masked + [y])
                else:
                    out_net = self.model(x_masked)

                x_hat = out_net["x_hat"]
                z = out_net["z"]

                for name, df in zip(self.data.view_names, x_hat):
                    imputed_datasets[name] = pd.DataFrame(
                        self.data.view_scalers[name].inverse_transform(df.tolist()),
                        index=self.data.samples,
                        columns=self.data.view_feature_names[name],
                    )

                    if name in {"copynumber"}:
                        imputed_datasets[name] = imputed_datasets[name].round()

                z = pd.DataFrame(z.tolist(), index=self.data.samples)
                z.columns = [f"Latent_{i+1}" for i in range(z.shape[1])]

                # Write to file
                for name, df in imputed_datasets.items():
                    df.round(5).to_csv(
                        f"{plot_folder}/files/{self.timestamp}_imputed_{name}.csv.gz",
                        compression="gzip",
                    )

                z.round(5).to_csv(
                    f"{plot_folder}/files/{self.timestamp}_latent_joint.csv.gz",
                    compression="gzip",
                )

    def load_vae_reconstructions(self, mode="nans_only", dfs=None):
        """
        Load imputed data and latent space from files. "nans_only" mode, original
        measurements are mantained and only NaNs are imputed. "all" mode all
        data is imputed.

        Parameters
        ----------
        mode : str, optional
            Loading mode of imputed data, by default "nans_only"

        Returns
        -------
        dict
            Dictionary of imputed dataframes
            pandas.DataFrame
                Latent space

        Raises
        ------
        ValueError
            If mode is not "nans_only" or "all"

        """

        if mode not in ["nans_only", "all"]:
            raise ValueError(f"Invalid mode {mode}")

        if dfs is None:
            dfs = self.data.dfs

        dfs_imputed = {}
        for n in dfs:
            df_file = f"{plot_folder}/files/{self.timestamp}_imputed_{n}.csv.gz"

            if not os.path.isfile(df_file):
                continue

            df_imputed = pd.read_csv(df_file, index_col=0)

            if mode == "nans_only":
                df_imputed = self.data.dfs[n].combine_first(df_imputed)

            dfs_imputed[n] = df_imputed

        # Load latent space
        joint_latent = pd.read_csv(
            f"{plot_folder}/files/{self.timestamp}_latent_joint.csv.gz", index_col=0
        )

        return dfs_imputed, joint_latent

    def register_loss(self, loss, extra_fields=None):
        r = {
            k: float(v)
            for k, v in loss.items()
            if type(v) == torch.Tensor and v.numel() == 1
        }

        if "reconstruction_views" in loss:
            for i, v in enumerate(loss["reconstruction_views"]):
                r[f"mse_{self.data.view_names[i]}"] = float(v)

        if extra_fields is not None:
            r.update(extra_fields)

        self.losses.append(r)

    def get_losses(self, cv_idx, epoch_idx, groupby=None):
        l = pd.DataFrame(self.losses).query(f"cv == {cv_idx} & epoch == {epoch_idx}")
        if groupby is not None:
            l = l.groupby(groupby).mean()
        return l

    def get_benchmark(self, cv_idx, epoch_idx, groupby=None, benchmark=None):
        l = pd.DataFrame(self.benchmark_scores).query(
            f"cv == {cv_idx} & epoch == {epoch_idx}"
        )

        if benchmark is not None:
            l = l.query(f"benchmark == '{benchmark}'")

        if groupby is not None:
            l = l.groupby(groupby).mean()

        return l

    def print_single_loss(self, loss_dict, pbar=None):
        ptxt = f"[{datetime.now().strftime('%H:%M:%S')}] Loss "
        ptxt += f" | Total={loss_dict['total']:.2f}"

        for k in loss_dict:
            if k not in ["cv", "epoch", "type", "total", "lr"] and "_" not in k:
                ptxt += f" | {k}={loss_dict[k]:.2f}"

        if pbar is not None:
            pbar.set_description(ptxt)
        else:
            print(ptxt)

    def print_losses(self, cv_idx, epoch_idx, pbar=None):
        l = self.get_losses(cv_idx, epoch_idx, groupby="type")

        ptxt = f"[{datetime.now().strftime('%H:%M:%S')}] CV={cv_idx:02}, Epoch={epoch_idx:03} Loss (train/val)"
        ptxt += f" | Total={l.loc['train', 'total']:.2f}/{l.loc['val', 'total']:.2f}"

        for k in l.columns:
            if k not in ["cv", "epoch", "type", "total", "lr"] and "_" not in k:
                ptxt += f" | {k}={l.loc['train', k]:.2f}/{l.loc['val', k]:.2f}"

        if self.verbose > 1:
            ptxt += f"\n[Benchmark scores (train/val)] "

            bench_df = self.get_benchmark(
                cv_idx, epoch_idx, groupby=["benchmark", "type"]
            ).reset_index()

            for b_name, b_df in bench_df.groupby("benchmark"):
                b_df = b_df.set_index("type")
                ptxt += f"{b_name}: {b_df.loc['train', 'score']:.2f}/{b_df.loc['val', 'score']:.2f} | "

        if pbar is not None:
            pbar.set_description(ptxt)
        else:
            print(ptxt)

    def save_losses(self):
        l = pd.DataFrame(self.losses)
        l.to_csv(f"{plot_folder}/files/{self.timestamp}_losses.csv", index=False)
        return l

    def load_losses_df(self):
        return pd.read_csv(f"{plot_folder}/files/{self.timestamp}_losses.csv")

    def save_model(self):
        if self.model is None:
            warnings.warn("No model to save. Run predictions first.")
        else:
            torch.save(
                self.model.state_dict(),
                f"{plot_folder}/files/{self.timestamp}_model.pt",
            )

    def load_model(self):
        model_path = f"{plot_folder}/files/{self.timestamp}_model.pt"

        if not os.path.isfile(model_path):
            warnings.warn(f"No model to load. {model_path}")
            raise FileNotFoundError

        self.model = self.initialize_model()
        self.model.load_state_dict(
            torch.load(
                f"{plot_folder}/files/{self.timestamp}_model.pt",
            )
        )

    def run_shap(self, n_samples=50, seed=42, explain_target="latent"):
        torch.manual_seed(seed)
        self.model.module.return_for_shap = explain_target
        if explain_target == "latent":
            batch_size = len(self.data.samples)
        elif explain_target == "drug_response":
            batch_size = len(self.data.samples) // 5
        else:
            raise ValueError(f"Invalid explain_target {explain_target}")

        self.model.eval()
        data_all = DataLoader(
            self.data,
            batch_size=batch_size,
            shuffle=False if explain_target == "latent" else True,
        )
        data = next(iter(data_all))
        x, y, x_nans, x_mask = data

        x = [m.to(self.device) for m in x]
        x_nans = [m.to(self.device) for m in x_nans]

        x_masked = [m[:, x_mask[i][0]].to(self.device) for i, m in enumerate(x)]
        x_nans_masked = [
            m[:, x_mask[i][0]].to(self.device) for i, m in enumerate(x_nans)
        ]
        y = y.to(self.device)

        if self.hypers["use_conditionals"]:
            input_list = x_masked + [y]
        else:
            input_list = x_masked

        explainer = shap.explainers._gradient._PyTorchGradient(
            self.model,
            input_list,
        )
        shap_values = explainer.shap_values(input_list, nsamples=n_samples)
        pickle.dump(
            shap_values,
            open(
                f"{plot_folder}/files/{self.timestamp}_shap_values_{explain_target}.pkl",
                "wb",
            ),
        )

    def _plot_lr_rates(self, ax):
        for e, lr in self.lrs:
            ax.axvline(e, color="black", linestyle="--", alpha=0.5, lw=0.3)
            ax.text(
                e,
                ax.get_ylim()[1],
                f"LR={lr:.0e}",
                ha="left",
                va="top",
                rotation=90,
                fontsize=4,
            )

    def plot_losses(self, losses_df=None, loss_terms=None, figsize=(3, 2)):
        if losses_df is None:
            losses_df = self.load_losses_df()

        # Plot total losses
        plot_df = pd.melt(losses_df, id_vars=["epoch", "type"], value_vars="total")

        _, ax = plt.subplots(1, 1, figsize=figsize, dpi=600)
        sns.lineplot(
            data=plot_df,
            x="epoch",
            y="value",
            hue="type",
            errorbar=("ci", 99),
            err_kws=dict(alpha=0.2, lw=0),
            ax=ax,
        )
        self._plot_lr_rates(ax)
        ax.set(
            title=f"Train and Validation Loss",
            xlabel="Epoch",
            ylabel="Loss",
        )
        ax.legend(
            title="Losses",
            loc="upper left",
            bbox_to_anchor=(1, 1),
        )
        PhenPred.save_figure(
            f"{plot_folder}/losses/{self.timestamp}_train_validation_loss"
        )

        # Plot reconstruction losses
        if loss_terms is None:
            cols = [
                c
                for c in losses_df
                if c not in ["cv", "epoch", "type", "total", "lr"] and "_" in c
            ]
        else:
            cols = loss_terms

        unique_prefix = {v.split("_")[0] for v in cols}
        for prefix in unique_prefix:
            plot_df = pd.melt(
                losses_df,
                id_vars=["epoch", "type"],
                value_vars=[c for c in cols if c.startswith(prefix)],
            )

            _, ax = plt.subplots(1, 1, figsize=figsize, dpi=600)
            sns.lineplot(
                data=plot_df,
                x="epoch",
                y="value",
                hue="variable",
                style="type",
                errorbar=("ci", 99),
                err_kws=dict(alpha=0.2, lw=0),
                ax=ax,
            )
            self._plot_lr_rates(ax)
            ax.legend(
                title="Losses",
                loc="upper left",
                bbox_to_anchor=(1, 1),
            )
            ax.set(
                title=f"Total loss",
                xlabel="Epoch",
                ylabel="Loss",
            )
            PhenPred.save_figure(
                f"{plot_folder}/losses/{self.timestamp}_{prefix}_losses"
            )

        # Plot loss terms
        if loss_terms is None:
            cols = [
                c
                for c in losses_df
                if c not in ["cv", "epoch", "type", "total", "lr"] and "_" not in c
            ]
        else:
            cols = loss_terms

        plot_df = pd.melt(
            losses_df,
            id_vars=["epoch", "type"],
            value_vars=cols,
        )

        _, ax = plt.subplots(1, 1, figsize=figsize, dpi=600)
        sns.lineplot(
            data=plot_df,
            x="epoch",
            y="value",
            hue="variable",
            style="type",
            errorbar=("ci", 99),
            err_kws=dict(alpha=0.2, lw=0),
            ax=ax,
        )
        self._plot_lr_rates(ax)
        ax.legend(
            title="Losses",
            loc="upper left",
            bbox_to_anchor=(1, 1),
        )
        ax.set(
            title=f"Total loss",
            xlabel="Epoch",
            ylabel="Loss",
        )
        PhenPred.save_figure(f"{plot_folder}/losses/{self.timestamp}_terms_losses")


from django.shortcuts import render

# Create your views here.
from django.views.generic import TemplateView
from home.models import CategoryTranslate, Category, ProductTranslate, Product, ProductTypeTranslate

class CategoryView(TemplateView):
    template_name = 'category/index.html'

    def get_header(seft, request):
        return render(request, seft.template_name)

    def get_context_data(self, **kwargs):
        # get category info with **kwargs
        categories = CategoryTranslate.objects.all().filter(lang_code='vn', category_id=kwargs.get('id'))
        # get all product of categories
        products = Product.objects.all().filter(category_id=kwargs.get('id'))
        # get all product of categories by language
        products_translate = ProductTranslate.objects.all().filter(lang_code='vn',product_id__in=products)
        # get all product types
        product_types = ProductTypeTranslate.objects.all().filter(lang_code='vn')
        # get all product special
        special_products_translate = ProductTranslate.objects.all().filter(lang_code='vn').select_related('product_id')
        context = {
            'category': categories[0],
            'products': products_translate,
            'product_types': product_types,
            'special_products': special_products_translate.order_by('product_id__rank')[:5]
        }
        return context


import numpy as np
import scipy.optimize as so

__all__ = ['_find_beta']

def _find_beta(func, xdata, ydata, min_func, nparms, **options):
    """
    Finds optimal initial values for the parameters for a function to be
    fit by some numerical method.
    """

    kw = dict(
        bounds = (-1e9, 1e9),
        fb_method = 'differential_evolution', # later eval
        de_strategy = 'best1bin',
        de_maxiter = None,
        de_popsize = 15,
        de_tol = 0.01,
        de_mutation = (0.5, 1),
        de_recombination = 0.7,
        de_seed = None,
        de_callback = None,
        de_disp = False,
        de_polish = True,
        de_init = 'latinhypercube',
    )

    kw.update(options)

    if kw['fb_method'].lower() == 'differential_evolution':
        try:
            x_max, y_max = max(xdata), max(ydata)
            x_min, y_min = min(xdata), min(ydata)
            xy_max, xy_min = max(x_max, y_max), min(x_min, y_min)
            if kw['bounds'] == None or kw['bounds'] == (-np.inf, np.inf):
                kw['bounds'] = [
                    [-max(abs(xy_max), abs(xy_min)),
                      max(abs(xy_max), abs(xy_min)),]
                    ] * nparms
            elif len(kw['bounds']) == 2 \
                    and type(kw['bounds'] not in (list, tuple, np.ndarray)):
                kw['bounds'] = [kw['bounds']] * nparms

            result = so.differential_evolution(
                min_func,
                kw['bounds'],
                strategy = kw['de_strategy'],
                maxiter = kw['de_maxiter'],
                popsize = kw['de_popsize'],
                tol = kw['de_tol'],
                mutation = kw['de_mutation'],
                recombination = kw['de_recombination'],
                seed = kw['de_seed'],
                callback = kw['de_callback'],
                disp = kw['de_disp'],
                polish = kw['de_polish'],
                init = kw['de_init'],
            )
            # you can introduce all kwargs in one go using comprehension
            # with keys, values removing 'de_' ([3:])
        except Exception as e:
            print(f"Error raised: {e!r}")
            raise ValueError("couldn't find beta")

        return result.x

    else:
        print(f"{kw['fb_method']!r} is not implemented yet")
        return

    return


from django.urls import reverse_lazy
from django.views.generic import TemplateView, CreateView, ListView, DeleteView

from todo.models import Todo

class TodoVueOnlyTV(TemplateView):
    template_name = 'todo/todo_vueonly.html'

# 필요한 속성들을 오버라이딩
class TodoCV(CreateView):
    model = Todo # 테이블
    fields = '__all__' # 폼을 만들기 위해 필드 필요. 모든 필드 사용
    template_name = 'todo/todo_form.html' # redirectView를 제외한 모든 뷰에서 사용되는 속성
    success_url = reverse_lazy('todo:list') # 리다이렉트 시킬 url

class TodoLV(ListView):
    model = Todo # 테이블
    template_name = 'todo/todo_list.html'

class TodoDelV(DeleteView):
    model = Todo # 특정 레코드를 삭제해야하므로 모델로 테이블을 지정
    template_name = 'todo/todo_confirm_delete.html'
    success_url = reverse_lazy('todo:list') # reverse() 또는 reverse_lazy() 사용해야. reverse()는 해당 라인 실행 시점 시작 시 urls.py가 로딩이 안된 상태..?? 뭐징


from collections import Counter
from itertools import combinations as cmb
def solution(orders, course):
    answer = []
    for c in course:
        tmp=Counter([''.join(sorted(i)) for o in orders for i in list((cmb(o,c)))])
        num=sorted(tmp.values())
        if len(tmp)==0 or num[-1]<2: continue
        for k,v in tmp.items():
            if v==num[-1]: answer.append(k)
    return sorted(answer)


#Oyunlarda mouse.move ise yaramaz.
import pyautogui

screen_width, screen_height = pyautogui.size()

pyautogui.FAILSAFE = False

center_w = int(screen_width/2)
center_h = int(screen_height/2)
screen_center = (center_w,center_h)

x = center_w
y = center_h

for i in range(50000):
    print(i)

pyautogui.moveRel(1000, 0) # Sağa hareket ettirir
pyautogui.moveRel(0, 1000) # Aşağı hareket ettirir

'''
#Cogu kutuphanenin icinde bu bulunur. Oyunlarda da mouse.move hareketini yapmayi saglar.
import win32api, win32con

for i in range(50):
    win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, x, y, 0, 0)
    pyautogui.click(x, y)
    x+=10
    #y+=10

'''

'''
#Oyun iclerinde de calisabilir, ancak vanguard gibi sistemler gercek bir usb fare ile mouse.move ozelligini kontrol ettirebilmek icin bu tarz seyleri engeller.
import pydirectinput

pydirectinput.moveRel(300, 0) # Sağa hareket ettirir
pydirectinput.moveRel(0, 300) # Aşağı hareket ettirir
pydirectinput.moveRel(-300, 0) # Sola hareket ettirir
pydirectinput.moveRel(0, -300) # Yukarı hareket ettirir

'''

'''
#Oyun iclerinde de calisabilir, ancak vanguard gibi sistemler gercek bir usb fare ile mouse.move ozelligini kontrol ettirebilmek icin bu tarz seyleri engeller.
from pynput.mouse import Button, Controller
import time

mouse = Controller()

# Read pointer position
print('The current pointer position is {0}'.format(
    mouse.position))

# Move pointer relative to current position
time.sleep(3)
mouse.move(-10000, 2000)
mouse.press(Button.left)
mouse.release(Button.left)
time.sleep(1)
mouse.move(200, -400)

# Set pointer position
mouse.position = (10, 20)
# Press and release
mouse.press(Button.left)
mouse.release(Button.left)

# Double click; this is different from pressing and releasing
# twice on macOS
mouse.click(Button.left, 2)

# Scroll two steps down
mouse.scroll(0, 2)

'''


from django.urls import path

from crm.api_views.products import (
    DisableProductsView,
    EnableProductsView,
    DeleteProductsView,
    CopyProductsView,
    ProductUpdateView,
)

app_name = "products"

urlpatterns = [
    path("disable/", DisableProductsView.as_view(), name="disable-products"),
    path("enable/", EnableProductsView.as_view(), name="enable-products"),
    path("delete/", DeleteProductsView.as_view(), name="delete-products"),
    path("copy/", CopyProductsView.as_view(), name="copy-products"),
    path("update/<pk>/", ProductUpdateView.as_view(), name="update"),
]


import google.generativeai as palm
import os
import yaml

# app config
valid_text_input = ['text', 't', 'txt']
valid_chat_input = ['chat', 'c', 'ch']
valid_chat_exit = ['exit', 'Exit', 'q', 'quit', 'Q', 'Quit']

def read_yaml(yamlFile: str) -> dict:
    with open(yamlFile, 'r') as f:
        yamlDict = yaml.safe_load(f)
    return yamlDict

def check_env():
    pass

if __name__ == "__main__":
    # determine if PaLM API key is present
    api_key = os.getenv('palm_key')
    # keep asking for PaLM API key until a valid key is provided
    while not api_key:
        new_key = input('No PaLM API key found. Enter new PaLM API key: ')
    # ADD PALM KEY VALIDATION HERE (len=39)
    palm.configure(api_key=os.getenv('palm_key'))

    # read config data from yaml
    config = read_yaml('config.yaml')
    # determine which generation method is desired
    generation_method = input("Choose a generation method (text or chat): ")
    # TEXT GENERATION
    if generation_method in valid_text_input:
        # to get text generation models
        models = [m for m in palm.list_models() if 'generateText' in m.supported_generation_methods]
        model = models[0].name
        # get user prompt
        prompt = input('Enter a prompt: ')
        print('-' * 100)
        # send data to the PaLM API if all required data is present
        if prompt:
            # send query data to PaLM API
            completion = palm.generate_text(model=model, prompt=prompt, temperature=config['temp'], max_output_tokens=config['max_output_tokens'])
            # print API response
            print(completion.result)
        # print an error message if prompt is empty
        else:
            print("No prompt provided. A prompt is required to use the PaLM API.")
    # CHAT GENERATION
    elif generation_method in valid_chat_input:
        continue_chat = True
        # start chat conversation
        chat_start_message = input('Start conversation: ')
        print('-' * 100)
        if chat_start_message in valid_chat_exit:
            continue_chat = False
        elif not chat_start_message:
            print('Prompt is empty. Use "quit" or "exit" to end chat.')
        else:
            response = palm.chat(messages=chat_start_message)
            print(f'PaLM: {response.last}')
            print('-' * 100)
            while continue_chat:
                chat_reply_message = input('Next query: ')
                print('-' * 100)
                if chat_reply_message in valid_chat_exit:
                    continue_chat = False
                elif not chat_reply_message:
                    print('Prompt is empty. Use "quit" or "exit" to end chat.')
                else:
                    response = response.reply(chat_reply_message)
                    print(f'PaLM: {response.last}')
                    print('-' * 100)
    # GENERATION NOT SUPPORTED
    else:
        print(f'Generation method "{generation_method}" is not supported.')


import sys, json

NUM_ROWS = 4
NUM_VARS = 2
def main():
    #args = {param.split('=')[0]: param.split('=')[1] for param in sys.argv[1:]}

    num_cols = NUM_VARS + 1
    width = 100 / num_cols
    html = '
';
    colgroup = '<colgroup>'
    for i in range(num_cols):
        colgroup += f'<col style="width: {width}%">'
    colgroup += '</colgroup>'
    html += colgroup + '
';
    html += f'
	Variables
'
    html += '
 Line number 	'
    for j in range(NUM_VARS):
        html += '<input class="coderunner-ui-element" name="variable_name">	'

    html += '
';
    for i in range(NUM_ROWS):
        html += '
<input class="coderunner-ui-element" name="line_number">	'
        for j in range(NUM_VARS):
            html += '<input class="coderunner-ui-element" name="variable_value">	'
        html += '
'
    html += '

'

    print(json.dumps({'html': html}))

main()


import argparse
import os
import copy
import shutil
import time

import torch
import torch.nn as nn
import torch.nn.parallel
import torch.backends.cudnn as cudnn
import torch.optim
import torch.utils.data
import torchvision.transforms as transforms
import torchvision.datasets as datasets

from fblib.util.classification.utils import convert_secs2time, time_string, time_file_str, AverageMeter
from fblib.networks.classification import se_resnet, mobilenet_v2, resnet, resnext
from fblib.util.mypath import Path

def parse_args():
    def str2bool(v):
        return v.lower() in ("yes", "true", "t", "1")

    parser = argparse.ArgumentParser(description='PyTorch ImageNet Training')
    parser.add_argument('--data', default=Path.db_root_dir('Imagenet'),
                        help='path to dataset')
    parser.add_argument('--arch', '-a', metavar='ARCH', default='x50')
    parser.add_argument('-j', '--workers', default=16, type=int, metavar='N',
                        help='number of data loading workers (default: 16)')
    parser.add_argument('--epochs', default=100, type=int, metavar='N',
                        help='number of total epochs to run')
    parser.add_argument('--start-epoch', default=0, type=int, metavar='N',
                        help='manual epoch number (useful on restarts)')
    parser.add_argument('-b', '--batch-size', default=256, type=int, metavar='N',
                        help='mini-batch size (default: 256)')
    parser.add_argument('--lr', '--learning-rate', default=0.1, type=float, metavar='LR',
                        help='initial learning rate')
    parser.add_argument('--momentum', default=0.9, type=float, metavar='M',
                        help='momentum')
    parser.add_argument('--weight-decay', '--wd', default=1e-4, type=float, metavar='W',
                        help='weight decay (default: 1e-4)')
    parser.add_argument('--print-freq', '-p', default=200, type=int, metavar='N',
                        help='print frequency (default: 100)')
    parser.add_argument('--resume', default='', type=str, metavar='PATH',
                        help='path to latest checkpoint (default: none)')
    parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true',
                        help='evaluate model on validation set')
    parser.add_argument('--n_gpu', type=int, default=8,
                        help='number of GPUs')
    parser.add_argument('--group_norm', type=str2bool, default=False,
                        help='Group Normalization')

    args = parser.parse_args()
    args.prefix = time_file_str()

    return args

def main():
    args = parse_args()
    best_prec1 = 0

    if not args.group_norm:
        save_dir = os.path.join(Path.exp_dir(), 'imagenet', args.arch)
    else:
        save_dir = os.path.join(Path.exp_dir(), 'imagenet', args.arch + '-GN')
    if not os.path.isdir(save_dir):
        os.makedirs(save_dir)
    log = open(os.path.join(save_dir, '{}.{}.log'.format(args.arch, args.prefix)), 'w')

    # create model
    print_log("=> creating model '{}'".format(args.arch), log)

    resol = 224
    if args.arch == 'res26':
        model = resnet.resnet26(pretrained=False, group_norm=args.group_norm)
    elif args.arch == 'res50':
        model = resnet.resnet50(pretrained=False, group_norm=args.group_norm)
    elif args.arch == 'res101':
        model = resnet.resnet101(pretrained=False, group_norm=args.group_norm)
    elif args.arch == 'x50':
        model = resnext.resnext50_32x4d(pretrained=False)
    elif args.arch == 'x101':
        model = resnext.resnext101_32x4d(pretrained=False)
    elif args.arch == 'res26-se':
        model = se_resnet.se_resnet26(num_classes=1000)
    elif args.arch == 'res50-se':
        model = se_resnet.se_resnet50(num_classes=1000)
    elif args.arch == 'res101-se':
        model = se_resnet.se_resnet101(num_classes=1000)
    elif args.arch == 'mobilenet-v2':
        model = mobilenet_v2.mobilenet_v2(pretrained=False, n_class=1000, last_channel=2048)

    print_log("=> Model : {}".format(model), log)
    print_log("=> parameter : {}".format(args), log)

    if args.arch.startswith('alexnet') or args.arch.startswith('vgg'):
        model.features = torch.nn.DataParallel(model.features, device_ids=list(range(args.n_gpu)))
        model.cuda()
    else:
        model = torch.nn.DataParallel(model, device_ids=list(range(args.n_gpu))).cuda()

    # define loss function (criterion) and optimizer
    criterion = nn.CrossEntropyLoss().cuda()

    optimizer = torch.optim.SGD(model.parameters(), args.lr,
                                momentum=args.momentum,
                                weight_decay=args.weight_decay,
                                nesterov=True)

    # optionally resume from a checkpoint
    if args.resume:
        if os.path.isfile(args.resume):
            print_log("=> loading checkpoint '{}'".format(args.resume), log)
            checkpoint = torch.load(args.resume)
            args.start_epoch = checkpoint['epoch']
            best_prec1 = checkpoint['best_prec1']
            model.load_state_dict(checkpoint['state_dict'])
            optimizer.load_state_dict(checkpoint['optimizer'])
            print_log("=> loaded checkpoint '{}' (epoch {})".format(args.resume, checkpoint['epoch']), log)
        else:
            raise ValueError("=> no checkpoint found at '{}'".format(args.resume))

    cudnn.benchmark = True

    # Data loading code
    traindir = os.path.join(args.data, 'train')
    valdir = os.path.join(args.data, 'val')
    normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                     std=[0.229, 0.224, 0.225])

    train_dataset = datasets.ImageFolder(
        traindir,
        transforms.Compose([
            transforms.RandomResizedCrop(resol),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor(),
            normalize,
        ]))

    train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=args.batch_size, shuffle=True,
                                               num_workers=args.workers, pin_memory=True, sampler=None)

    val_loader = torch.utils.data.DataLoader(
        datasets.ImageFolder(valdir, transforms.Compose([
            transforms.Resize(256),
            transforms.CenterCrop(resol),
            transforms.ToTensor(),
            normalize,
        ])),
        batch_size=args.batch_size, shuffle=False,
        num_workers=args.workers, pin_memory=True)

    if args.evaluate:
        validate(val_loader, model, criterion)
        return

    filename = os.path.join(save_dir, 'checkpoint.{}.{}.pth.tar'.format(args.arch, args.prefix))
    bestname = os.path.join(save_dir, 'best.{}.{}.pth.tar'.format(args.arch, args.prefix))

    start_time = time.time()
    epoch_time = AverageMeter()
    for epoch in range(args.start_epoch, args.epochs):
        lr = adjust_learning_rate(optimizer, epoch, args)

        need_hour, need_mins, need_secs = convert_secs2time(epoch_time.val * (args.epochs - epoch))
        need_time = '[Need: {:02d}:{:02d}:{:02d}]'.format(need_hour, need_mins, need_secs)
        print_log(' [{:s}] :: {:3d}/{:3d} ----- [{:s}] {:s} LR={:}'.format(args.arch, epoch, args.epochs, time_string(),
                                                                           need_time, lr), log)

        # train for one epoch
        train(train_loader, model, criterion, optimizer, epoch, log, args)

        # evaluate on validation set
        prec1 = validate(val_loader, model, criterion, log, args)

        # remember best prec@1 and save checkpoint
        is_best = prec1 > best_prec1
        best_prec1 = max(prec1, best_prec1)
        save_checkpoint({
            'epoch': epoch + 1,
            'arch': args.arch,
            'state_dict': model.state_dict(),
            'best_prec1': best_prec1,
            'optimizer': optimizer.state_dict(),
            'args': copy.deepcopy(args),
        }, is_best, filename, bestname)
        # measure elapsed time
        epoch_time.update(time.time() - start_time)
        start_time = time.time()
    log.close()

def train(train_loader, model, criterion, optimizer, epoch, log, args):
    batch_time = AverageMeter()
    data_time = AverageMeter()
    losses = AverageMeter()
    top1 = AverageMeter()
    top5 = AverageMeter()

    # switch to train mode
    model.train()

    end = time.time()
    for i, (input, target) in enumerate(train_loader):
        # measure data loading time
        data_time.update(time.time() - end)

        target_var = target.cuda(non_blocking=True)
        input_var = input.requires_grad_()

        # compute output
        output = model(input_var)
        loss = criterion(output, target_var)

        # measure accuracy and record loss
        prec1, prec5 = accuracy(output.data, target_var, topk=(1, 5))
        losses.update(loss.item(), input.size(0))
        top1.update(prec1.item(), input.size(0))
        top5.update(prec5.item(), input.size(0))

        # compute gradient and do SGD step
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        # measure elapsed time
        batch_time.update(time.time() - end)
        end = time.time()

        if i % args.print_freq == 0:
            print_log('Epoch: [{0}][{1}/{2}]\t'
                      'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
                      'Data {data_time.val:.3f} ({data_time.avg:.3f})\t'
                      'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                      'Prec@1 {top1.val:.3f} ({top1.avg:.3f})\t'
                      'Prec@5 {top5.val:.3f} ({top5.avg:.3f})'.format(
                epoch, i, len(train_loader), batch_time=batch_time,
                data_time=data_time, loss=losses, top1=top1, top5=top5), log)

def validate(val_loader, model, criterion, log, args):
    batch_time = AverageMeter()
    losses = AverageMeter()
    top1 = AverageMeter()
    top5 = AverageMeter()

    # switch to evaluate mode
    model.eval()

    end = time.time()

    with torch.no_grad():
        for i, (input_var, target) in enumerate(val_loader):
            target_var = target.cuda(non_blocking=True)

            # compute output
            output = model(input_var)
            loss = criterion(output, target_var)

            # measure accuracy and record loss
            prec1, prec5 = accuracy(output.data, target_var, topk=(1, 5))
            losses.update(loss.item(), input_var.size(0))
            top1.update(prec1.item(), input_var.size(0))
            top5.update(prec5.item(), input_var.size(0))

            # measure elapsed time
            batch_time.update(time.time() - end)
            end = time.time()

            if i % args.print_freq == 0:
                print_log('Test: [{0}/{1}]\t'
                          'Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
                          'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                          'Prec@1 {top1.val:.3f} ({top1.avg:.3f})\t'
                          'Prec@5 {top5.val:.3f} ({top5.avg:.3f})'.format(
                    i, len(val_loader), batch_time=batch_time, loss=losses,
                    top1=top1, top5=top5), log)

    print_log(' * Prec@1 {top1.avg:.3f} Prec@5 {top5.avg:.3f} Error@1 {error1:.3f}'.format(top1=top1, top5=top5,
                                                                                error1=100 - top1.avg), log)

    return top1.avg

def save_checkpoint(state, is_best, filename, bestname):
    torch.save(state, filename)
    if is_best:
        shutil.copyfile(filename, bestname)

def adjust_learning_rate(optimizer, epoch, args):
    """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
    lr = args.lr * (0.1 ** (epoch // 30))
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr
    return lr

def accuracy(output, target, topk=(1,)):
    """Computes the precision@k for the specified values of k"""
    maxk = max(topk)
    batch_size = target.size(0)

    _, pred = output.topk(maxk, 1, True, True)
    pred = pred.t()
    correct = pred.eq(target.view(1, -1).expand_as(pred))

    res = []
    for k in topk:
        correct_k = correct[:k].view(-1).float().sum(0, keepdim=True)
        res.append(correct_k.mul_(100.0 / batch_size))
    return res

def print_log(print_string, log):
    print("{}".format(print_string))
    log.write('{}\n'.format(print_string))
    log.flush()

if __name__ == '__main__':
    main()


from bootstrap4.renderers import FormRenderer
from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _

from .models import DBF, DBFChunkedUpload
from .validation import is_valid_dbf

class DBFForm(forms.Form):
    uploaded_by = forms.ModelChoiceField(
        queryset=User.objects.all(), widget=forms.HiddenInput()
    )
    chunked_upload_id = forms.IntegerField(
        required=False, widget=forms.HiddenInput()
    )
    filename = forms.CharField(required=False, widget=forms.HiddenInput())
    export_date = forms.DateField(label=_("Data da exportação"))
    notification_year = forms.IntegerField(label=_("Ano de notificação"))
    abbreviation = forms.ChoiceField(
        choices=DBF.ABBREVIATION, label=_("Abrangência")
    )
    municipio = forms.CharField(
        label=_("Nome do município (opcional)"), required=False
    )

    def clean(self):
        cleaned_data = super(DBFForm, self).clean()
        chunked_upload_id = cleaned_data.get("chunked_upload_id")
        user = cleaned_data.get("uploaded_by")
        # If the user tries to give the id of a chunked_upload by
        # another user, or an inexistent id, we raise a validation
        # error.
        try:
            uploaded_file = DBFChunkedUpload.objects.get(
                id=chunked_upload_id, user=user
            )
        except DBF.DoesNotExist:
            raise ValidationError(
                _(
                    "Houve um erro durante o envio do arquivo. "
                    "Por favor, tente novamente."
                )
            )
        # This might be a performance problem for really large DBFs
        is_valid_dbf(uploaded_file.file, cleaned_data["notification_year"])
        return cleaned_data

class FormRendererWithHiddenFieldErrors(FormRenderer):
    def get_fields_errors(self):
        form_errors = []
        for field in self.form:
            if field.errors:
                form_errors += field.errors
        return form_errors


# TODO Error Handling & Reporting
# TODO Platform Compatibility
# TODO GUI Polishing
# TODO Code comments to each functionality
# TODO Start, Stop and Resume functionality
# TODO Proper indication of started scanning operations
# TODO Faster port scanning if possible
# TODO App name and icon changes and complete .exe

import subprocess
import sys
import csv
from subprocess import check_output
import requests
from PyQt5.QtCore import QThread, pyqtSignal, Qt, QObject
from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
import threading
import nmap

class IP:
    def __init__(self, ip, hostname, mac, manufacturer, osys, status):
        self.ip = ip
        self.hostname = hostname
        self.mac = mac
        self.manufacturer = manufacturer
        self.os = osys
        self.status = status

class Pass:
    def __int__(self, ip, command, range, port, method):
        self.ip = ip
        self.command = command
        self.range = range
        self.port = port
        self.method = method

class Port:
    def __init__(self, port, name, product, version):
        self.port = port
        self.name = name
        self.product = product
        self.version = version

def run():
    app = QApplication(sys.argv)
    w = MainWindow()
    widget = QtWidgets.QStackedWidget()
    widget.addWidget(w)
    widget.setGeometry(300, 100, 1400, 900)
    widget.show()
    try:
        sys.exit(app.exec_())
    except:
        print("Exiting")

parent_threads = []
threads = []

# noinspection PyUnresolvedReferences
class MainThread(QThread):

    update = pyqtSignal(int)

    def __init__(self, *args):
        super(QThread, self).__init__()
        if len(args) == 3:
            self.__w = args[0]
            self.__subnet = args[1]
            self.__p = args[2]
            self.__arg = len(args)
        elif len(args) == 6:
            self.__w = args[0]
            self.__ip = args[1]
            self.__command = args[2]
            self.__range = args[3]
            self.__port = args[4]
            self.__method = args[5]
            self.__arg = len(args)

    def run(self):
        if self.__arg == 3:
            val = MainWindow.ping(self.__w, self.__p, self.__subnet)
            self.update.emit(val)
        elif self.__arg == 6:
            if self.__method == 0:
                val = MainWindow.port_scan_all(self.__w, self.__ip, self.__command)
                self.update.emit(val)
            elif self.__method == 1:
                val = MainWindow.port_scan_singal(self.__w, self.__ip, self.__port, self.__command)
                self.update.emit(val)
            elif self.__method == 2:
                val = MainWindow.port_scan_range(self.__w, self.__ip, self.__range, self.__command)
                self.update.emit(val)
            elif self.__method == 3:
                val = MainWindow.port_scan_common(self.__w, self.__ip, self.__command)
                self.update.emit(val)

# noinspection PyUnresolvedReferences
class MainWindow(QMainWindow):
    p_val = []
    ips = []

    def __init__(self):
        super(MainWindow, self).__init__()
        loadUi("App.ui", self)
        self.pushButton.clicked.connect(self.scan)
        self.pushButton_2.clicked.connect(self.port_scan)
        self.actionStatus.changed.connect(self.hide_status)
        self.actionIP.changed.connect(self.hide_ip)
        self.actionMac.changed.connect(self.hide_mac)
        self.actionHost_Name.changed.connect(self.hide_host_name)
        self.actionOS.changed.connect(self.hide_os)
        self.actionManufacturer.changed.connect(self.hide_manu)
        self.actionTime.changed.connect(self.hide_time)
        self.comboBox.currentIndexChanged.connect(self.selected_ports_disabler)
        self.actionDownload_as_csv_file.triggered.connect(self.download)
        self.actionAbout.triggered.connect(self.about)

    def about(self):
        msg = QtWidgets.QMessageBox()
        msg.setWindowTitle('About')
        msg.setGeometry(800, 500, 900, 900)
        msg.setText('This is a Ping Sweep program with some port scanning functionalities and a GUI')
        msg.setIcon(QtWidgets.QMessageBox.Information)
        x = msg.exec_()

    def download(self):
        header = ['', 'Status', 'IP', 'Mac', 'Host Name', 'OS', 'Manufacturer']
        f = open('ping_data.csv', 'w', newline='')
        writer = csv.writer(f)
        writer.writerow(header)
        for i in range(len(MainWindow.ips)):
            x = self.treeWidget.topLevelItem(i)
            row = []
            for p in range(7):
                row.append(x.text(p))
            writer.writerow(row)
            cc = x.childCount()
            if cc > 0:
                for q in range(cc):
                    ch = x.child(q)
                    row = []
                    for p in range(4):
                        row.append(ch.text(p))
                    writer.writerow(row)
        f.close()

    def selected_ports_disabler(self):
        if self.comboBox.currentIndex() == 1:
            self.spinBox_3.setEnabled(True)
            self.spinBox.setEnabled(False)
            self.spinBox_2.setEnabled(False)
        elif self.comboBox.currentIndex() == 2:
            self.spinBox_3.setEnabled(False)
            self.spinBox.setEnabled(True)
            self.spinBox_2.setEnabled(True)
        else:
            self.spinBox_3.setEnabled(False)
            self.spinBox.setEnabled(False)
            self.spinBox_2.setEnabled(False)

    def hide_status(self):
        if not self.actionStatus.isChecked():
            self.treeWidget.setColumnHidden(1, True)
        else:
            self.treeWidget.setColumnHidden(1, False)

    def hide_ip(self):
        if not self.actionIP.isChecked():
            self.treeWidget.setColumnHidden(2, True)
        else:
            self.treeWidget.setColumnHidden(2, False)

    def hide_mac(self):
        if not self.actionMac.isChecked():
            self.treeWidget.setColumnHidden(3, True)
        else:
            self.treeWidget.setColumnHidden(3, False)

    def hide_host_name(self):
        if not self.actionHost_Name.isChecked():
            self.treeWidget.setColumnHidden(4, True)
        else:
            self.treeWidget.setColumnHidden(4, False)

    def hide_os(self):
        if not self.actionOS.isChecked():
            self.treeWidget.setColumnHidden(5, True)
        else:
            self.treeWidget.setColumnHidden(5, False)

    def hide_manu(self):
        if not self.actionManufacturer.isChecked():
            self.treeWidget.setColumnHidden(6, True)
        else:
            self.treeWidget.setColumnHidden(6, False)

    def hide_time(self):
        if not self.actionTime.isChecked():
            self.treeWidget.setColumnHidden(7, True)
        else:
            self.treeWidget.setColumnHidden(7, False)

    def scan(self):
        MainWindow.p_val = []
        MainWindow.ips = []
        self.pushButton.setEnabled(False)
        self.pushButton_2.setEnabled(False)
        self.textEdit.clear()
        self.pBar.reset()
        self.pBar.setValue(0)
        self.treeWidget.clear()
        config = check_output('ipconfig /all', universal_newlines=True)
        networks = config.split('IPv4 Address. . . . . . . . . . . :')
        maxp = (len(networks) - 1) * 255
        self.pBar.setMaximum(maxp)
        for i in range(len(networks) - 1):
            tt = threading.Thread(target=MainWindow.multi_network, args=[self, networks, i])
            tt.start()

    def port_scan(self):
        MainWindow.p_val = []
        selected_ips = []
        self.pushButton.setEnabled(False)
        self.pushButton_2.setEnabled(False)
        self.pBar.reset()
        self.pBar.setValue(0)
        self.pBar.setMaximum(len(MainWindow.ips))
        ai = self.comboBox_3.currentText()
        method = self.comboBox_2.currentIndex()
        command = ''
        if method == 0:
            command = '-sT'
        elif method == 1:
            command = '-sS'
        elif method == 2:
            command = '-sX'
        elif method == 3:
            command = '-sA'
        elif method == 4:
            command = '-sU'
        selected = self.comboBox.currentText()
        if ai == 'All Hosts':
            if selected == 'all':
                for ip in MainWindow.ips:
                    tht = MainThread(self, ip, command, '', '', 0)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)
            elif selected == 'singal port':
                for ip in MainWindow.ips:
                    p = self.spinBox_3.value()
                    tht = MainThread(self, ip, command, '', p, 1)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)
            elif selected == 'range':
                for ip in MainWindow.ips:
                    fp = self.spinBox.value()
                    lp = self.spinBox_2.value()
                    range = ''
                    if fp < lp:
                        range = str(fp) + '-' + str(lp)
                    elif lp > fp:
                        range = str(lp) + '-' + str(fp)
                    elif fp == lp:
                        range = str(lp)
                    tht = MainThread(self, ip, command, range, '', 2)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)
            elif selected == 'common':
                for ip in MainWindow.ips:
                    tht = MainThread(self, ip, command, '', '', 3)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)
        elif ai == 'Individual Hosts':
            for ip in MainWindow.ips:
                t = self.treeWidget.findItems(str(ip), Qt.MatchFlag.MatchExactly, 2)[0]
                if t.checkState(0) == 2:
                    selected_ips.append(ip)
            self.pBar.setMaximum(len(selected_ips))
            if selected == 'all':
                for ip in selected_ips:
                    tht = MainThread(self, ip, command, '', '', 0)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)
            elif selected == 'singal port':
                for ip in selected_ips:
                    p = self.spinBox_3.value()
                    tht = MainThread(self, ip, command, '', p, 1)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)
            elif selected == 'range':
                for ip in selected_ips:
                    fp = self.spinBox.value()
                    lp = self.spinBox_2.value()
                    range = ''
                    if fp < lp:
                        range = str(fp) + '-' + str(lp)
                    elif lp > fp:
                        range = str(lp) + '-' + str(fp)
                    elif fp == lp:
                        range = str(lp)
                    tht = MainThread(self, ip, command, range, '', 2)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)
            elif selected == 'common':
                for ip in selected_ips:
                    tht = MainThread(self, ip, command, '', '', 3)
                    tht.update.connect(self.evt_update)
                    tht.start()
                    tht.wait(30)

    def port_scan_all(self, ip, method):
        out = False
        args = 'nmap ' + method + ' -sV -p 1-65535 -O -Pn'
        nm = nmap.PortScanner()
        try:
            nm.scan(hosts=ip, arguments=args, timeout=900)
        except nmap.PortScannerTimeout as exc:
            print(ip + '  Scan Complete is timed out')
            return 0
        xx = nm.scanstats()
        timee = xx['elapsed']
        if len(nm.all_hosts()) == 0:
            out = True
        if out:
            print(ip + '  Scan Complete is out')
            return 0
        if not out:
            for proto in nm[ip].all_protocols():
                for port in nm[ip].all_tcp():
                    if nm[ip][proto][port]['state'] == 'open' or nm[ip][proto][port]['state'] == 'filtered':
                        pp = Port(port, nm[ip]['tcp'][int(port)]['name'], nm[ip]['tcp'][int(port)]['product'],
                                  nm[ip]['tcp'][int(port)]['version'])
                        os = nm[ip]['osmatch'][0]['name']
                        MainWindow.add_child(self, ip, pp, timee, os)
                        print('done  ' + ip + ' ' + str(port))
            print(ip + '  Scan Complete')
            return 0

    def port_scan_range(self, ip, range, method):
        out = False
        args = 'nmap ' + method + ' -sV -p ' + str(range) + ' -O -Pn'
        nm = nmap.PortScanner()
        try:
            nm.scan(hosts=ip, arguments=args, timeout=700)
        except nmap.PortScannerTimeout as exc:
            print(ip + '  Scan Complete is timed out')
            return 0
        xx = nm.scanstats()
        timee = xx['elapsed']
        if len(nm.all_hosts()) == 0:
            out = True
        if out:
            print(ip + '  Scan Complete is out')
            return 0
        if not out:
            for proto in nm[ip].all_protocols():
                for port in nm[ip].all_tcp():
                    if nm[ip][proto][port]['state'] == 'open' or nm[ip][proto][port]['state'] == 'filtered':
                        pp = Port(port, nm[ip]['tcp'][int(port)]['name'], nm[ip]['tcp'][int(port)]['product'],
                                  nm[ip]['tcp'][int(port)]['version'])
                        os = nm[ip]['osmatch'][0]['name']
                        MainWindow.add_child(self, ip, pp, timee, os)
                        print('done  ' + ip + ' ' + str(port))
            print(ip + '  Scan Complete')
            return 0

    def port_scan_common(self, ip, method):
        out = False
        args = 'nmap ' + method + ' -sV --top-ports 1000 -O -Pn'
        nm = nmap.PortScanner()
        try:
            nm.scan(hosts=ip, arguments=args, timeout=600)
        except nmap.PortScannerTimeout as exc:
            print(ip + '  Scan Complete is timed out')
            return 0
        xx = nm.scanstats()
        timee = xx['elapsed']
        if len(nm.all_hosts()) == 0:
            out = True
        if out:
            print(ip + '  Scan Complete is out')
            return 0
        if not out:
            for proto in nm[ip].all_protocols():
                for port in nm[ip].all_tcp():
                    if nm[ip][proto][port]['state'] == 'open' or nm[ip][proto][port]['state'] == 'filtered':
                        pp = Port(port, nm[ip]['tcp'][int(port)]['name'], nm[ip]['tcp'][int(port)]['product'],
                                  nm[ip]['tcp'][int(port)]['version'])
                        os = nm[ip]['osmatch'][0]['name']
                        MainWindow.add_child(self, ip, pp, timee, os)
                        print('done  ' + ip + ' ' + str(port))
            print(ip + '  Scan Complete')
            return 0

    def port_scan_singal(self, ip, p, method):
        out = False
        args = 'nmap ' + method + ' -sV -p ' + str(p) + ' -O -Pn'
        nm = nmap.PortScanner()
        try:
            nm.scan(hosts=ip, arguments=args, timeout=150)
        except nmap.PortScannerTimeout as exc:
            print(ip + '  Scan Complete is timed out')
            return 0
        xx = nm.scanstats()
        timee = xx['elapsed']
        if len(nm.all_hosts()) == 0:
            out = True
        if out:
            print(ip + '  Scan Complete is out')
            return 0
        if not out:
            for proto in nm[ip].all_protocols():
                for port in nm[ip].all_tcp():
                    if nm[ip][proto][port]['state'] == 'open':
                        pp = Port(port, nm[ip]['tcp'][int(port)]['name'], nm[ip]['tcp'][int(port)]['product'],
                                  nm[ip]['tcp'][int(port)]['version'])
                        os = nm[ip]['osmatch'][0]['name']
                        MainWindow.add_child(self, ip, pp, timee, os)
                        print('done  ' + ip + ' ' + str(port))
        print(ip + '  Scan Complete')
        return 0

    def evt_update(self, val):
        MainWindow.p_val.append(val)
        self.pBar.setValue(len(MainWindow.p_val))
        if self.pBar.value() == self.pBar.maximum():
            self.pBar.reset()
            self.pBar.setValue(0)
            self.pushButton.setEnabled(True)
            self.pushButton_2.setEnabled(True)

    def add_row(self, entry):
        item = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item.setCheckState(0, Qt.CheckState.Unchecked)
        item.setText(1, entry.status)
        item.setText(2, entry.ip)
        item.setText(3, entry.mac)
        item.setText(4, entry.hostname)
        item.setText(5, entry.os)
        item.setText(6, entry.manufacturer)
        MainWindow.ips.append(entry.ip)

    def add_child(self, ip, entry, time, os):
        t = self.treeWidget.findItems(str(ip), Qt.MatchFlag.MatchExactly, 2)[0]
        t.setText(5, os)
        t.setText(7, time)
        item = QtWidgets.QTreeWidgetItem(t)
        item.setText(1, str(entry.port))
        item.setText(2, entry.name)
        item.setText(3, entry.product)
        item.setText(4, entry.version)

    def ping(self, p, subnet):
        status = 'alive'
        try:
            o = check_output('ping -a ' + str(subnet) + str(p) + ' -n 1 ', universal_newlines=True)
        except subprocess.CalledProcessError as exc:
            o = exc.output
            a = check_output('arp -a', universal_newlines=True)
            if a.find(str(subnet) + str(p) + ' ') > -1:
                status = status + '/filtered'
            else:
                return 0
        if o.find('unreachable') > -1:
            return 0
        try:
            r = o.split('Pinging ')
            t = r[1].rsplit(' with')
            ih = t[0]
            h = ih.split(' [')
            if len(h) == 2:
                host = h[0]
                q = h[1].rsplit(']')
                ip = q[0]
            else:
                host = 'Unknown'
                ip = h[0]

            if status == 'alive':
                r = t[1].split('TTL=')
                t = r[1].rsplit('Ping ')
                ttl = t[0]
                if int(ttl) == 32:
                    os = 'Windows 95/98/ME'
                elif int(ttl) == 64:
                    os = 'Linux/Unix'
                elif int(ttl) == 128:
                    os = 'Windows XP/7/8/2003/2008'
                elif int(ttl) == 255:
                    os = 'Solaris'
            else:
                os = 'Unknown'
            j = check_output('ipconfig /all', universal_newlines=True)
            tmp1 = j.split('IPv4 Address. . . . . . . . . . . :')
            for i in range(len(tmp1) - 1):
                tmp2 = tmp1[i + 1].splitlines()
                tmp3 = tmp2[0].replace(" ", "").split('.')
                tmp4 = tmp3[3].split('(')
                tmp3[3] = tmp4[0]
                tmp5 = '.'.join(tmp3)
                if ip == tmp5:
                    mainIp = tmp5
                    break
                else:
                    mainIp = ''
            a = check_output('arp -a', universal_newlines=True)
            if ip == mainIp:
                j = check_output('ipconfig /all', universal_newlines=True)
                tmp1 = j.split(str(ip))
                tmp2 = tmp1[0].rsplit('Physical Address. . . . . . . . . :', 1)
                tmp3 = tmp2[1].splitlines()
                mac = ''.join(tmp3[0].split())
                response = requests.request("GET", 'https://api.maclookup.app/v2/macs/' + mac)
                if response.status_code == 200:
                    tmp1 = response.text.split('company')
                    tmp2 = tmp1[1].split(',', 1)
                    tmp3 = tmp2[0].split('":"')
                    tmp4 = tmp3[1].split('"')
                    company = tmp4[0]
                else:
                    company = 'Unknown'
                entry = IP(str(ip), host, mac, company, os, status)
                MainWindow.add_row(self, entry)
                return 0
            v = a.split(ip + ' ')
            m = v[1].split('dynamic')
            ma = m[0]
            mac = ma.replace(" ", "")
            response = requests.request("GET", 'https://api.maclookup.app/v2/macs/' + mac)
            if response.status_code == 200:
                tmp1 = response.text.split('company')
                tmp2 = tmp1[1].split(',', 1)
                tmp3 = tmp2[0].split('":"')
                tmp4 = tmp3[1].split('"')
                company = tmp4[0]
                if company == '':
                    company = 'Unknown'
            else:
                company = 'Unknown'
            entry = IP(str(ip), host, mac, company, os, status)
            MainWindow.add_row(self, entry)
            return 0
        except IndexError:
            print('An out of bounds index error has accord')

    def multi_network(self, networks, i):
        ipv4 = networks[i + 1].splitlines()
        mask = ipv4[0].replace(" ", "").split('.')
        mask[3] = ''
        subnet = '.'.join(mask)
        self.textEdit.insertPlainText(subnet + '0/24  ')
        for x in range(255):
            mt = MainThread(self, subnet, x)
            mt.update.connect(self.evt_update)
            mt.start()
            threads.append(mt)
            mt.wait(15)

t = threading.Thread(target=run)
t.start()


from __future__ import absolute_import
from __future__ import print_function
import numpy as np
import os
import sys
import optparse
import csv
import time
import matplotlib.pyplot as plt
# user's python files
from intelligentModel2PhaseCoord import callUppaalStratego
import detectorData
import generateRouteForTwenty
import calculateWaitingTime
import plottingPurpose

# we need to import python modules from the $SUMO_HOME/tools directory
if 'SUMO_HOME' in os.environ:
    tools = os.path.join(os.environ['SUMO_HOME'], 'tools')
    sys.path.append(tools)
else:
    sys.exit("please declare environment variable 'SUMO_HOME'")
from sumolib import checkBinary  # noqa
import traci  # noqa

# loop and area detectors
areaDetectorFifty = detectorData.areaDetectorFifty
areaDetectorFiftySeqIndex = detectorData.areaDetectorFiftySeqIndex
loopDetectorFifity = detectorData.loopDetectorFifity
loopDetectorFiftySeqIndex = detectorData.loopDetectorFiftySeqIndex
loopAreaDetectorFifity = detectorData.loopAreaDetectorFifity
throughputLoopDetectors = detectorData.throughputLoopDetectors

totalWaitingTime = np.zeros(20,dtype=int)
tolSum =[]
phaseNS = np.zeros(20,dtype=int)
phaseWE = np.zeros(20,dtype=int) + 2
phaseToNS = np.zeros(20,dtype=int) + 1
phaseToEW = np.zeros(20,dtype=int) + 3
ic_minGreen = np.zeros(20,dtype=int) + 8
yellow = np.zeros(20,dtype=int) + 4
timeInPhase = np.zeros(20,dtype=int)
nextPhase = np.zeros(20,dtype=int)
phase = np.zeros(20,dtype=int)
count_time = [False] * 20
phaseTime = np.zeros(20,dtype=int)

# intelligent variable declaration
previousPhase = np.zeros(20,dtype=int)
maximumTimer_A = np.zeros(20,dtype=int) + 40
maximumTimer_B = np.zeros(20,dtype=int) + 40
loadCapacity = [15,20,25,30,35,45,55,75,100,120]
maxGreenTimeforLoad = [50,60,70,90,100,110,120,130,140,150]
intelligentTimer = [20,25,30,35,40,45,45,50,50,50]

trafficLightId = detectorData.trafficLightId

class TrafficLight:
    totalWaitingTime = 0 ; totalQueueLength = 0 ; totalCo2Emission = 0 ; totalCoEmission = 0

    def __init__(self, trlId, areaDetectors,loopDetectors,loopAreaDetectors,sInd,sIndLoop,debug):
        self.trlId = trlId
        self.areaDetectors = areaDetectors
        self.loopDetectors = loopDetectors
        self.loopAreaDetectors = loopAreaDetectors
        self.sIndex = sInd
        self.sIndexLoop = sIndLoop
        self.debug = debug
        self.direction_A = 0
        self.direction_B = 0

    def getData(self,func, dets):
        numDet = len(dets)
        res = [0] * numDet
        for deti in range(0, numDet):
            res[deti] = func(dets[deti])
        return res

    # get the arrival car list
    def getArrivalCars(self):
        indx = self.sIndex
        carsArrival = self.getData(traci.lanearea.getLastStepVehicleNumber, self.areaDetectors)
        carArrival = [ sum(carsArrival[indx[0]:indx[1]]),sum(carsArrival[indx[2]:indx[3]])
                       ,sum(carsArrival[indx[4]:indx[5]]),sum(carsArrival[indx[6]:indx[7]])]
        self.direction_A = sum(carArrival[0:2])
        self.direction_B = sum(carArrival[2:4])
        if self.debug:
            print("In Intersection %s: Arrival cars [Left Right Up Down]:%s"%(self.trlId,carArrival))
        return carArrival

    # get the jammed car list
    def getJammedCars(self):
        indx = self.sIndex
        carsJammed = self.getData(traci.lanearea.getLastStepHaltingNumber, self.areaDetectors)
        carJammed = [sum(carsJammed[indx[0]:indx[1]]), sum(carsJammed[indx[2]:indx[3]])
            , sum(carsJammed[indx[4]:indx[5]]), sum(carsJammed[indx[6]:indx[7]])]
        if self.debug:
            print("In Intersection %s: Jammed cars [Left Right Up Down]:%s" % (self.trlId, carJammed))
        return carJammed

        # get the waiting car list

    def getWaitingCars(self):
        indx = self.sIndex
        carsWaiting = self.getData(traci.lanearea.getLastStepHaltingNumber, self.areaDetectors)
        carWaiting = [sum(carsWaiting[indx[0]:indx[2]]), sum(carsWaiting[indx[2]:indx[4]])
            , sum(carsWaiting[indx[4]:indx[6]]), sum(carsWaiting[indx[6]::])]
        self.totalWaitingTime += sum(carWaiting)
        if self.debug:
            print("In Intersection %s: Jammed cars [Left Right Up Down]:%s" % (self.trlId, carWaiting))
        return carWaiting
    # get the jammed cars length in meters
    def getJammedCarsLength(self):
        indx = self.sIndex
        carsJammedLength = self.getData(traci.lanearea.getJamLengthMeters, self.areaDetectors)
        carJammedLength = [sum(carsJammedLength[indx[0]:indx[2]]), sum(carsJammedLength[indx[2]:indx[4]])
            , sum(carsJammedLength[indx[4]:indx[6]]), sum(carsJammedLength[indx[6]::])]
        self.totalQueueLength += sum(carJammedLength)
        if self.debug:
            print("In Intersection %s: Jammed cars Length [Left Right Up Down]:%s" % (self.trlId, carJammedLength))
        return carJammedLength

    # getting loop detector data for loop controller
    def getLoopDetectorData(self):
        indx = self.sIndexLoop
        carsCrossed = self.getData(traci.inductionloop.getLastStepVehicleNumber, self.loopDetectors)
        carsCrossedNow = [sum(carsCrossed[indx[0]:indx[1]]), sum(carsCrossed[indx[2]:indx[3]])
            , sum(carsCrossed[indx[4]:indx[5]]), sum(carsCrossed[indx[6]:indx[7]])]
        if self.debug:
            print("In Intersection %s: Loop detector data [Left Right Up Down]:%s" % (self.trlId, carsCrossedNow))
        return carsCrossedNow

    # minor road small lenght area detector data
    def getLoopAreaDetectorData(self):
        carsLoopArea = self.getData(traci.lanearea.getLastStepVehicleNumber, self.loopAreaDetectors)
        if self.debug:
            print("In Intersection %s: loop area detectors [Up Down]:%s" % (self.trlId, carsLoopArea))
        return carsLoopArea

    def dataForLoopController(self):
        cData = np.hstack( (self.getLoopDetectorData(),self.getLoopAreaDetectorData()) )
        return cData

    # Co2 and Co  emission calculation
    def getEmission(self):
        indx = self.sIndex
        emissionOutCo2 = 0
        emissionOutCo = 0
        carsCo2Emission = self.getData(traci.lanearea.getLastStepVehicleIDs, self.areaDetectors)
        out = list(sum(carsCo2Emission, ()))
        for i in range(len(out)):
            emissionOutCo2 += traci.vehicle.getCO2Emission(out[i])
            emissionOutCo += traci.vehicle.getCOEmission(out[i])
        self.totalCo2Emission += emissionOutCo2
        self.totalCoEmission += emissionOutCo
        if self.debug:
            pass
            # print("In Intersection %s: Co2 Emission (mg):%s" % (self.trlId, self.totalCo2Emission))
            # print("In Intersection %s: Co Emission (mg):%s" % (self.trlId, self.totalCoEmission))
        return emissionOutCo2,emissionOutCo

    def dataForIntelligentController(self):
        cIData = np.hstack(( self.getArrivalCars(),self.getJammedCars()))
        cIJammedLength = self.getJammedCarsLength()
        self.getEmission()
        return cIData,cIJammedLength

def getThroughput(func, dets):
    numDet = len(dets)
    res = [0] * numDet
    for deti in range(0,numDet):
        res[deti] = func(dets[deti])
    return res

# def motorWaiting(areaDetectors):
#     count = 0
#     vehicleIds = traci.lanearea.getLastStepVehicleIDs(areaDetectors)
#     motorId = traci.lanearea.getLastStepHaltingNumber(areaDetectors)
#     print("vehicle ids:",vehicleIds)
#     motorString = str(vehicleIds)
#     for i in vehicleIds:
#         if i.startswith("motorCycle",0,10):
#             count += 1
#     for j in vehicleIds:
#         print("vehicle waitng time:",traci.vehicle.getWaitingTime(j))
#     return count
# strategoTimer = [0,0,0,0,0]
# areaDetectors = [1,2,16,18]

greenTimer = np.arange(len(trafficLightId))
redTimer = np.arange(len(trafficLightId))

t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)
# ysample = random.sample(range(0, 500), 250)
# print("ysample:",ysample)
xdata = []
ydata = []
x1data = []
y1data = []

def oneTimePlotIntialization(x_end,y_end):
    plt.show()
    axes = plt.gca()
    axes.set_xlim(0, x_end)
    axes.set_ylim(0, y_end)
    line, = axes.plot(xdata, ydata, 'r-')
    line1, = axes.plot(x1data, y1data, 'g-')
    return line,line1

def plotGraph(x_data,y_data,x1_data,y1_data,line,line1):

    xdata.append(x_data)
    ydata.append(y_data)

    x1data.append(x1_data)
    y1data.append(y1_data)

    line.set_xdata(xdata)
    line.set_ydata(ydata)

    line1.set_xdata(x1data)
    line1.set_ydata(y1data)

    plt.draw()
    plt.pause(1e-17)
    time.sleep(0.1)

    # loop controllers

def extend(ext, bound, extTime):
    ext = ext + extTime
    return ext

def actuatedController(trlId, phaseNS, phaseToNS, phaseWE, phaseToEW, maxGreenNS, maxGreenEW, yellow, ic_minGreen,
                   phaseNow, timeInPhaseNow, phaseTimeNow, count_timeNow, nextPhaseNow, loopDet, areaDet):
    if phaseNow == phaseNS[trlId] or phaseNow == phaseWE[trlId]:  # we controll the green time
        traci.trafficlights.setPhaseDuration(trafficLightId[trlId], 5000)
    loopDetInfo = loopDet
    areDetInfo = areaDet
    if phaseNow == phaseWE[trlId]:  # Green in B direction
        if timeInPhaseNow >= maxGreenEW[trlId] or phaseTimeNow <= 0:
            # Goto yellow
            traci.trafficlights.setPhase(trafficLightId[trlId], phaseToNS[trlId])
            phaseNow = phaseToNS[trlId]
            nextPhaseNow = phaseNS[trlId]
            timeInPhaseNow = 0
        else:  # Check if we shoud extend the phase timer
            phaseTimeNow -= 1
            if loopDetInfo[0] >= 1 or loopDetInfo[1] >= 1:
                phaseTimeNow = extend(phaseTimeNow, maxGreenEW[trlId], 4.0)
            cars_on_AreDet = sum(areDetInfo) > 0
            if cars_on_AreDet:  # Make sure the time ticks while we stay in one phase
                phaseTimeNow += 1
        timeInPhaseNow += 1
    elif phaseNow == phaseNS[trlId]:  # Green in A direction
        if timeInPhaseNow >= maxGreenNS[trlId] or phaseTimeNow <= 0:
            # Goto yellow
            traci.trafficlights.setPhase(trafficLightId[trlId], phaseToEW[trlId])
            phaseNow = phaseToEW[trlId]
            nextPhaseNow = phaseWE[trlId]
            timeInPhaseNow = 0
        else:
            cars_on_AreDet = sum(areDetInfo) > 0
            if loopDetInfo[0] == 1 or loopDetInfo[1] == 1 or cars_on_AreDet:
                count_timeNow = True
            if count_timeNow:  # This phase is the resting phase
                if loopDetInfo[2] == 1 or loopDetInfo[3] == 1:
                    phaseTimeNow = extend(phaseTimeNow, maxGreenNS[trlId], 4.0)
                if loopDetInfo[2] == 1 or loopDetInfo[3] == 1:
                    phaseTimeNow = extend(phaseTimeNow, maxGreenNS[trlId], 4.0)
                timeInPhaseNow += 1
                phaseTimeNow -= 1
    else:  # In yellow
        if timeInPhaseNow == yellow[trlId]:
            # At the end of yellow the timeing variables are reset, the min green time is 10
            timeInPhaseNow = 0
            phaseTimeNow = ic_minGreen[trlId]
            phaseNow = nextPhaseNow
            traci.trafficlights.setPhase(trafficLightId[trlId], phaseNow)
            # traci.trafficlights.setPhaseDuration(idTL, 60)
            count_timeNow = False
        else:
            timeInPhaseNow += 1
    phase[trlId] = phaseNow
    nextPhase[trlId] = nextPhaseNow
    phaseTime[trlId] = phaseTimeNow
    timeInPhase[trlId] = timeInPhaseNow
    count_time[trlId] = count_timeNow

    # return phaseNow

def writeFile(row):
    # create file(if no file) and append data
    with open('trafficWaiting.csv', 'a') as csvFile:
        writer = csv.writer(csvFile)
        writer.writerow(row)
    csvFile.close()
def loadMaximumActuated(load):
    if load == "Case1Low":
        maxGreenEW = np.zeros(20, dtype=int) + 25
        maxGreenNS = np.zeros(20, dtype=int) + 40
    if load == "Case1Mid":
        maxGreenEW = np.zeros(20, dtype=int) + 35
        maxGreenNS = np.zeros(20, dtype=int) + 55
    if load == "Case1High":
        maxGreenEW = np.zeros(20, dtype=int) + 55
        maxGreenNS = np.zeros(20, dtype=int) + 85
    if load == "Case2":
        maxGreenEW = np.zeros(20, dtype=int) + 50
        maxGreenNS = np.zeros(20, dtype=int) + 60
    if load == "Case3":
        maxGreenEW = np.zeros(20, dtype=int) + 40
        maxGreenNS = np.zeros(20, dtype=int) + 40
    if load == "Case4":
        maxGreenEW = np.zeros(20, dtype=int) + 65
        maxGreenNS = np.zeros(20, dtype=int) + 35

    return maxGreenEW,maxGreenNS
def emissionCalculation(vehicleList,mode):
    sum = 0
    for vehId in vehicleList:
        if mode == "CO":
            sum += traci.vehicle.getCOEmission(vehId)
        if mode == "CO2":
            sum += traci.vehicle.getCO2Emission(vehId)
        if mode == "WaitingTime":
            if traci.vehicle.getSpeed(vehId) < 0.1:
                sum += 1
    return sum
def run():
    """execute the TraCI control loop"""
    step = 0
    strategoTimerTicks = 0
    crossedCars = 0
    # load fixed and actuated timing for traffic light
    for i in range(len(trafficLightId)):
        traci.trafficlights.setProgram(trafficLightId[i],options.load)

    maxGreenEW,maxGreenNS = loadMaximumActuated(options.load)

    print("%s controller is working in %s now............." %(options.controller,options.load))
    totalWaitingTime = 0
    totalCo2 = 0.0
    totalCo = 0.0
    # line,line1 = oneTimePlotIntialization(3000,15)
    nextPhaseNow = np.arange(250).reshape(5,50)
    trafficLightObj = list()
    queueLength = 0
    waitingTime = 0
    carJam = []
    carArrv = []
    timeVerJammedCars =[]
    timeVerQueuedCars =[]
    totalCOemision = []
    totalCO2emision = []
    totalWaitingtimeFrom = []
    for i in range(20):
        trafficLightObj.append( TrafficLight(str(i), areaDetectorFifty[i], loopDetectorFifity[i], loopAreaDetectorFifity[i], areaDetectorFiftySeqIndex[i],loopDetectorFiftySeqIndex[i],False))
    # t1 = TrafficLight("1", areaDet, loopDet, loopArea, sIndex,sIndexLoop,False)
    # t2 = TrafficLight("1", areaDet, loopDet, loopArea, sIndex,sIndexLoop,False)
    # while traci.simulation.getMinExpectedNumber() > 0:
    currentIntelligentTimer = 20
    oneTimeRun = True
    previousPhase = np.zeros(20, dtype=int)
    currentLoad = 100
    stepPerLoad = []
    # while traci.simulation.getMinExpectedNumber() > 0:
    while step <= int(options.step):
        # traci.switch("static")
        # traci.simulationStep()
        # y = sum(t1.getJammedCars())
        # y1 = sum(t1.getArrivalCars())
        # # plotGraph(step, y, step, y1, line, line1)
        # intl, ql = t1.dataForIntelligentController()
        # print("Total waiting Time in Static:",t1.totalWaitingTime)
        # traci.switch("loop")
        traci.simulationStep()
        step = step + 1
        jamCarsOneStep = 0
        queueCarsOneStep = 0
# ------------------------- Output data ---------------------------------------------------------------------------
        for outdata in range(0, 20):
            jamCarsOneStep += sum(trafficLightObj[outdata].getWaitingCars())
            queueCarsOneStep += sum(trafficLightObj[outdata].getJammedCarsLength())
        timeVerJammedCars.append(jamCarsOneStep)
        timeVerQueuedCars.append(queueCarsOneStep)

        # -----------------------------------------------------------------------------------------------------
        throughput = getThroughput(traci.inductionloop.getLastStepVehicleNumber, throughputLoopDetectors)
        crossedCars = crossedCars+ sum(throughput)
        #------------------ Emission calculation ---------------------------------------
        vehIdsList = traci.vehicle.getIDList()
        totalCOemision.append(emissionCalculation(vehIdsList,"CO"))
        totalCO2emision.append(emissionCalculation(vehIdsList,"CO2"))
        totalWaitingtimeFrom.append(emissionCalculation(vehIdsList,"WaitingTime"))
        # # print("vehicle ids:",traci.vehicle.getIDList())
        # for vehId in vehIdsList:
        #     # print("Co2 emission:",traci.vehicle.getCO2Emission(vehId))
        #     # print("Co emission:", traci.vehicle.getCOEmission(vehId))
        #     totalCOemision.append(traci.vehicle.getCO2Emission(vehId))
        #     if traci.vehicle.getSpeed(vehId) < 0.1:
        #         print("Waiting time: ", traci.vehicle.getSpeed(vehId),vehId)

        # print("crossed cars",crossedCars)
        # print("\rCars passed count:  {}".format(crossedCars), end="")
        # print("\rTime Step        :  {}".format(step), end="")
        # print("\n")
        # for outdata in range(0,20):
        #     trafficLightObj[outdata].getJammedCarsLength()
        #     trafficLightObj[outdata].getArrivalCars()
        #     # trafficLightObj[outdata].getWaitingCars()
        #     # queueLength += trafficLightObj[outdata].totalQueueLength
        #     # waitingTime += trafficLightObj[outdata].totalWaitingTime
        #     # print("In Traffic light %s: %s Hours" %(outdata+1,trafficLightObj[outdata].totalWaitingTime))
        #     print("Traffic Light: %s Arrival Cars: %s " % (outdata+ 1 , trafficLightObj[outdata].getArrivalCars()))
        #     print("Traffic Light: %s Jammed Cars: %s " % (outdata + 1, trafficLightObj[outdata].getJammedCars()))
            # print("Traffic Light: %s waiting Cars: %s " % (outdata + 1, trafficLightObj[outdata].getWaitingCars()))
            # print("Traffic Light: %s Detector details: %s " % (outdata + 1, trafficLightObj[outdata].dataForLoopController()))
    #     #------------------------------------------------------------------------------------------------------

        # get the current loaded capacity

        if step % 100 == 0:

            for trfLgt in range(0, 20):
                loadInADirection = trafficLightObj[trfLgt].direction_A
                loadInBDirection = trafficLightObj[trfLgt].direction_B
                for lc in range(len(loadCapacity)):
                    if loadCapacity[lc] >= loadInADirection:
                        maximumTimer_A[trfLgt] = maxGreenTimeforLoad[lc]
                    if loadCapacity[lc] >= loadInBDirection:
                        maximumTimer_B[trfLgt] = maxGreenTimeforLoad[lc]
                        break
            for trf in range(len(trafficLightId)):
                currentLoad = currentLoad + sum(trafficLightObj[trf].getArrivalCars())
            stepPerLoad.append(currentLoad)
            for lc in range(len(loadCapacity)):
                if (loadCapacity[lc] * 30 ) >= currentLoad:
                    currentIntelligentTimer = intelligentTimer[lc]
                    currentLoad = 0
                    break
            # writing time step and load
        # ------------------------cheking purpose-----------------------------
        # for a in range(16, 17):
        #     print("cars arrival in %s is %s" % (a + 1, trafficLightObj[a].getArrivalCars()))
        #     print("cars jammed in %s is %s" % (a + 1, trafficLightObj[a].getJammedCars()))
        # print("loop dec value:",throughput)
        # print("crossed cars:",crossedCars)
        # arrr= trafficLightObj[0].getArrivalCars()
        # print("A direction Cars:",AreaOne_A)
        # print("B direction Cars:",AreaOne_B)

        # y1 = sum(t2.getJammedCars())
        # y1 = sum(t1.getArrivalCars())
        # intl,ql = t2.dataForIntelligentController()
        # print("Loop controller", t1.dataForLoopController())
        # t1.getEmission()
        # print("Inte controller",intl )
        # print("Inte controller length",ql )
        # print("Total waiting Time in Loop:",t2.totalWaitingTime)
        # print("Total waiting Time:",t1.totalQueueLength)

        # ------------------------------------ Loop Controller ------------------------------------------------------
        if options.controller == "Actuated":
         for i in range(20):

            loopDet1 = trafficLightObj[i].getLoopDetectorData()
            loopArea1 = trafficLightObj[i].getLoopAreaDetectorData()
            actuatedController(i,phaseNS,phaseToNS,phaseWE,phaseToEW,maxGreenNS,maxGreenEW,yellow,ic_minGreen,phase[i],timeInPhase[i],phaseTime[i],
                                count_time[i],nextPhase[i],loopDet1,loopArea1)
         if oneTimeRun:
            print("--------------Actuated controller is working now:------------ ")
            oneTimeRun = False

         # ------------------------------------ Intelligent Controller ------------------------------------------------------

         # calling intelligent controller
        if options.controller == "Intelligent":
         if oneTimeRun:
            print("--------------------------------Intelligent controller is working now:--------------------------------------")
            oneTimeRun = False
         for a in range(0,20):
            # print("cars arrival in %s is %s" %(a+1,trafficLightObj[a].getArrivalCars()))
            # print("cars jammed in %s is %s" %(a+1,trafficLightObj[a].getJammedCars()))
            carJam.append(trafficLightObj[a].getJammedCars())
            carArrv.append(trafficLightObj[a].getArrivalCars())

        # print("cars jammed list:",carJam)
         carsJam = []
         carsArrv = []
         for b in range(0,20):
            carsJam = carsJam + carJam[b]
            carsArrv = carsArrv + carArrv[b]
         carJam.clear()
         carArrv.clear()
         if strategoTimerTicks <= 0:
            nextPhaseNow = callUppaalStratego(carsJam,carsArrv,greenTimer,redTimer,maximumTimer_B,maximumTimer_A,previousPhase)
            print("Intelligent Timer : %s step: %s" % (currentIntelligentTimer,step))
            strategoTimerTicks = currentIntelligentTimer
            for a in range(0, 20):
                print("cars arrival,Jam in %s %s is %s phase:%s" %(a+1,trafficLightObj[a].getArrivalCars(),trafficLightObj[a].getJammedCars(),nextPhaseNow[a][0:20]))
                print("GreenTimer-A: %s GreenTimer-B: %s Max-A: %s Max-B: %s" %(redTimer[a],greenTimer[a],maximumTimer_A[a],maximumTimer_B[a]))
         else:
            for i in range(0,20):
                    traci.trafficlight.setPhase(trafficLightId[i], nextPhaseNow[i][strategoTimerTicks])
                    previousPhase[i] = nextPhaseNow[i][currentIntelligentTimer-3]
                    if nextPhaseNow[i][strategoTimerTicks] == 2:
                        greenTimer[i] += 1
                    if nextPhaseNow[i][strategoTimerTicks] == 0:
                        redTimer[i] += 1
                    if nextPhaseNow[i][strategoTimerTicks] == 3:
                        redTimer[i] = 0
                        greenTimer[i] = 0
            strategoTimerTicks -= 1

    traci.close()
    detWaitingTime = np.arange(20)
    detQueueLength = np.arange(20)
    #
    for i in range(20):
        print("In Traffic light %s: %s Hours" % (i + 1, trafficLightObj[i].totalWaitingTime))
        detWaitingTime[i] = trafficLightObj[i].totalWaitingTime
        detQueueLength[i] = trafficLightObj[i].totalQueueLength
    detWaitingTime = np.around(detWaitingTime / 3600,2)
    detQueueLength = np.around(detQueueLength/1000 ,2)
    print("Waiting time from detectors:",sum(detWaitingTime))
    print("Queue length from detectors:", sum(detQueueLength))
    print("time verses cars:",timeVerJammedCars)
    # writing required data into file
    plottingPurpose.writeToFile("trafficWaiting.csv", stepPerLoad)
    calculateWaitingTime.writingPlottingData(detWaitingTime,options.controller+"Bar",options.load)
    calculateWaitingTime.writingPlottingData(timeVerJammedCars,options.controller+"Line",options.load)
    plottingPurpose.writeResult(sum(totalCOemision), sum(totalCO2emision), sum(totalWaitingtimeFrom), sum(detQueueLength) * 1000, crossedCars / step, options.controller + options.step + "-" + options.load, True)
    sys.stdout.flush()

def get_options(controllerNameEx,cases):
    optParser = optparse.OptionParser()
    controllerName = ("Intelligent","Fixed-Time","Actuated")
    optParser.add_option("--nogui", action="store_true",
                         default=True, help="run the commandline version of sumo")
    optParser.add_option("--controller", type="string", dest="controller", default= controllerNameEx)
    optParser.add_option("--step", type="string", dest="step", default="7200")
    optParser.add_option("--load", type="string", dest="load", default=cases)
    options, args = optParser.parse_args()
    return options

# this is the main entry point of this script
if __name__ == "__main__":

    controllerName = ('Fixed-Time', 'Actuated','Intelligent')
    cases = ["Case1Low","Case1Mid","Case1High","Case2","Case3","Case4"]
    # controllerName = [controllerName[1],controllerName[2]]
    # cases = ['Case2','Case3','Case4']
    for c in cases:
        plottingPurpose.writeToFile("results/resultOfExperiments.csv", "----------------------------------------------------" + c +
                         "------------------------------------------------------")
        for i in controllerName:
            options = get_options(i,c)
    # this script has been called from the command line. It will start sumo as a
    # server, then connect and run
            if options.nogui:
                sumoBinary = checkBinary('sumo')
            else:
                sumoBinary = checkBinary('sumo-gui')
            # gerenate route for the cases
            generateRouteForTwenty.generate_routefileAhmFiftyOsm(c, "ahm2PhaseOsmFiftyLoop.rou.xml", 278)

    # first, generate the route file for this simulation
    # generate_routefile()

    # this is the normal way of using traci. sumo is started as a
    # subprocess and then the python script connects and runs
    # traci.start(["sumo", "-c", "sim1.sumocfg"], label="sim1")
    # traci.start(["sumo", "-c", "sim2.sumocfg"], label="sim2")
            traci.start([sumoBinary, "-c", "twentyJunctionsAhm/ahm2PhaseOsmLoop.sumocfg","--tripinfo-output", "results/"+options.controller+"Tripfile.xml"],label="static")
    # traci.start([sumoBinary, "-c", "twentyJunctionsAhm/ahm2PhaseOsmLoop.sumocfg", "--tripinfo-output",
    #              "twentyJunctionsAhm/tripinfoInte.xml", "--emission-output", "twentyJunctionsAhm/emiInte.xml"],label="loop")
            run()