import torch
import time
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader, random_split, SubsetRandomSampler
from torch.optim.lr_scheduler import LambdaLR
import pytorch_lightning as pl
import torchmetrics
import numpy as np
from sklearn.cluster import KMeans
import os
import plotly.express as px

import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

class UDAModel(pl.LightningModule):
    def __init__(self, feature_extractor, classification_head, n_classes,
                       source_dataset, target_dataset, contrastive_only=False,
                       tau=1., b=0.75, lmbda=1.4,
                       pseudo_filter_threshold=0.9, track_grad_norm=False,
                       explicit_negative_sampling_threshold=0.5, grad_clip=1.5,
                       batch_size=64, num_workers=48, pretrain_num_epochs=0,
                       negative_sampling=None, remove_mismatched=False,
                       total_epochs=None, class_names=None):
        super().__init__()
        self.save_hyperparameters(ignore=['feature_extractor', 'classification_head', 'source_dataset', 'target_dataset'])

        self.track_grad_norm = track_grad_norm
        self.automatic_optimization = not self.track_grad_norm
        self.grad_clip = grad_clip

        self.contrastive_only = contrastive_only
        assert not (contrastive_only and pretrain_num_epochs > 0)

        self.n_classes = n_classes
        # The last layer should be smth giving (N, out_features)
        self.feature_extractor = feature_extractor
        self.classification_head = classification_head
        self.classification_loss = nn.CrossEntropyLoss()

        self.tau = tau
        self.explicit_negative_sampling_threshold = explicit_negative_sampling_threshold
        self.pseudo_filter_threshold = pseudo_filter_threshold
        self.b = b
        self.lmbda = lmbda
        self.batch_size = batch_size
        self.num_workers = num_workers
        self.pretrain_num_epochs = pretrain_num_epochs
        self.negative_sampling = self.check_negative_sampling(negative_sampling)
        self.remove_mismatched = remove_mismatched

        self.total_epochs = self.check_total_epochs(total_epochs)
        self.class_names = self.check_class_names(class_names)

        self.train_source_dataset, self.val_source_dataset = source_dataset
        self.train_target_dataset, self.val_target_dataset = target_dataset
        self.valid_target_samples = list(range(len(self.train_target_dataset)))

        self.accuracy_metric = torchmetrics.Accuracy(task='multiclass', num_classes=n_classes, average=None)
        #self.precision_metric = torchmetrics.Precision(num_classes=n_classes, average=None)
        #self.recall_metric = torchmetrics.Recall(num_classes=n_classes, average=None)

    def check_class_names(self, class_names):
        if class_names is None:
            class_names = np.arange(self.n_classes)

        return class_names

    def check_negative_sampling(self, negative_sampling):
        """
        Checks correctness of 'negative_sampling' parameter.
        """

        negative_sampling_options = [None, 'soft', 'hard', 'random']
        if negative_sampling in negative_sampling_options:
            return negative_sampling
        else:
            raise Exception(f"Wrong negative sampling option {negative_sampling}. Available options are: {negative_sampling_options}.")

    def check_total_epochs(self, total_epochs):
        if total_epochs is None:
            raise Exception("total_epochs should be not 'None'")
        elif not isinstance(total_epochs, int):
            raise Exception(f"total_epochs should be int, but is '{type(total_epochs)}'")
        else:
            return total_epochs

    def __call__(self, inp, domain_label):
        features = self.feature_extractor(inp, domain_label)

        return self.classification_head(features)

    def configure_optimizers(self):
        sgd = torch.optim.SGD([
            { 'params': self.feature_extractor.parameters(), 'lr': 1e-3 },
            { 'params': self.classification_head.parameters(), 'lr': 1e-2 },
        ], momentum=0.9)

        def mult_factor(epoch):
            p = epoch / self.total_epochs

            return (1 + 10 * p) ** (-self.b)

        scheduler = LambdaLR(sgd, mult_factor)

        return {
            "optimizer": sgd,
            "lr_scheduler": { "scheduler": scheduler },
        }

    def calculate_class_centers(self):
        dataloader = self.dataloader_source_for_centroids()

        accum = torch.zeros((self.n_classes, self.feature_extractor.in_features), device=self.device)

        for x, y, y_real in dataloader:
            assert torch.all(y == y_real), 'y != y_real in calculate_class_centers'
            x = x.to(self.device)
            y = y.to(self.device)
            features = self.feature_extractor(x, 0)

            y = y.view(y.size(0), 1).expand(-1, features.size(1))

            batch_class_means = torch.zeros_like(accum, dtype=torch.float32, device=self.device)\
                                     .scatter_add_(0, y, features)
            accum += batch_class_means

        labels_count = torch.from_numpy(np.bincount(self.train_source_dataset.labels, minlength=self.n_classes))
        labels_count = labels_count.to(self.device)
        initial_centers = (accum / labels_count.float().unsqueeze(1)).cpu().numpy()
        initial_centers /= np.linalg.norm(initial_centers, axis=1)[:, np.newaxis]

        return initial_centers

    def get_target_features(self):
        dataloader = self.dataloader_target_for_clustering()
        all_features = []
        for x, _, _ in dataloader:
            x = x.to(self.device)
            features = self.feature_extractor(x, 1)
            features = features.cpu().numpy()
            all_features.append(features)
        all_features = np.vstack(all_features)

        return all_features

    def visualize_pseudo_labeling(self):
        real_labels = self.train_target_dataset.real_labels
        labels = self.train_target_dataset.labels

        pairs = np.vstack((real_labels, labels))
        unique_pairs, counts = np.unique(pairs, axis=1, return_counts=True)
        fig = px.scatter_3d(x=unique_pairs[0, :], y=unique_pairs[1, :], z=counts)
        fig.show()

    def class_analysis(self, dataset):
        labels = dataset.labels
        real_labels = dataset.real_labels
        self.logger.experiment.add_scalar(f'Mislabeled fraction', np.mean(labels != real_labels), self.current_epoch)

        # find unassigned labels
        # unassigned_labels = set(range(31)).difference(np.unique(labels).tolist())
        # self.logger.experiment.add_text('unassigned labels',
        #                                str(unassigned_labels), self.current_epoch)

        # for each class find the distribution of assigned classes
        # label_stats = {}
        # for i in range(31):
        #     ilabels = labels[real_labels == i]
        #     if len(ilabels) == 0:
        #         continue
        #     self.logger.experiment.add_histogram(f'class {i} assigned to:',
        #                                          ilabels, self.current_epoch,
        #                                          bins=31)
        #     self.logger.experiment.add_scalar(f'Class {i} mislabeled fraction', (ilabels != i).sum() / len(ilabels), self.current_epoch)

    def filter_after_cluster(self, features, centers):
        # Normalize the centers so they are on the unit-sphere
        centers /= np.linalg.norm(centers, axis=1)[:, np.newaxis]
        # Calculate similarities between target features and cluster centers
        sims = features @ centers.T
        # Similarity with the closest cluster center
        max_sims = sims.max(axis=1)
        assert len(max_sims) == len(features)
        # Take only samples which are 'close enough' to class centroids
        mask = max_sims > self.pseudo_filter_threshold
        self.logger.experiment.add_scalar(f'Close enough targets', np.sum(mask), self.current_epoch)

        # If the setting is to not allow mislabeled samples in training dataset
        if self.remove_mismatched:
            mismatch_mask = self.train_target_dataset.real_labels == self.train_target_dataset.labels

            mask &= mismatch_mask

        # Save indices of valid samples - they are 'close enough' (and optionally, are not mislabeled)
        # This list will be used in 'train_dataloader' function
        self.valid_target_samples = np.arange(len(self.train_target_dataset))[mask]
        np.random.shuffle(self.valid_target_samples)

        self.logger.experiment.add_scalar(f'Remaining targets', np.sum(mask), self.current_epoch)

    def on_train_epoch_start(self):
#        if self.pretrain_num_epochs <= self.current_epoch:
        logger.info("Do pseudo-labeling")
        self.feature_extractor.eval()

        # Define a clusterizer
        clusterizer = KMeans(n_clusters=self.n_classes, n_init=1)
        with torch.no_grad():
            # Calculate class centroids on the source domain
            initial_centers = self.calculate_class_centers()
            # Initialize cluster positions
            clusterizer.set_params(init=initial_centers)
            # Collect features for target samples
            all_features = self.get_target_features()
            # Do clusterization
            clusterizer.fit(all_features)
            # Update target labels
            self.train_target_dataset.labels = clusterizer.labels_
            # Log stats about the results of pseudo-labeling
            self.class_analysis(self.train_target_dataset)
            # Filter out unwanted samples from training data.
            self.filter_after_cluster(all_features, clusterizer.cluster_centers_)
            self.log('unique labels', len(np.unique(self.train_target_dataset.labels)))

        self.feature_extractor.train()

    def classification_step(self, batch):
        x, y, y_real = batch
        assert torch.all(y == y_real), "y != y_real in classification step"

        features = self.feature_extractor(x, 0)
        if self.contrastive_only:
            # In contrastive only mode I want only contrastive loss to have impact on feature encoder weights.
            # Therefore, I detach 'features' from the computation graph, so classification loss impacts only classification head.
            logger.info("contrastive_only - Detach features")
            features = features.detach()

        pred = self.classification_head(features)

        probs = F.softmax(pred.detach(), dim=1)
        probs = probs.max(dim=1).values.mean().item()

        self.log('mean_pred_prob', probs, on_epoch=True, on_step=False)

        class_loss = self.classification_loss(pred, y)

        return class_loss

    def get_same_class(self, batch, cls):
        x, y, _ = batch
        return x[y == cls]

    def analyze_negative_samples(self, anchor, negatives, positives, anchor_type):
        if anchor_type == 'source':
            # since anchor is from source, its class is unambiguous
            # Therefore, we'll check correctness of pseudo-labeling in target batch
            # For that we'll use actual labels of targets.
            x, y, _ = anchor
            neg_x, _, neg_y_real = negatives
            pos_x, _, pos_y_real = positives

            false_negatives_sims = neg_x[neg_y_real == y]
            if len(false_negatives_sims) != 0:
                #self.logger.experiment.add_histogram('source_anchor, false negative sims',
                #                                     false_negatives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('source_anchor, false negative sims, max',
                                                  false_negatives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('source_anchor, false negative sims, mean',
                                                  false_negatives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'source_anchor, false negative sims, anchor {y}',
                #                                     false_negatives_sims,
                #                                     self.global_step)

            true_negatives_sims = neg_x[neg_y_real != y]
            if len(true_negatives_sims) != 0:
                #self.logger.experiment.add_histogram('source_anchor, true negative sims',
                #                                     true_negatives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('source_anchor, true negative sims, max',
                                                  true_negatives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('source_anchor, true negative sims, mean',
                                                  true_negatives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'source_anchor, true negative sims, anchor {y}',
                #                                     true_negatives_sims,
                #                                     self.global_step)

            false_positives_sims = pos_x[pos_y_real != y]
            if len(false_positives_sims) != 0:
                #self.logger.experiment.add_histogram('source_anchor, false positive sims',
                #                                     false_positives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('source_anchor, false positive sims, max',
                                                  false_positives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('source_anchor, false positive sims, mean',
                                                  false_positives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'source_anchor, false positive sims, anchor {y}',
                #                                     false_positives_sims,
                #                                     self.global_step)

            true_positives_sims = pos_x[pos_y_real == y]
            if len(true_positives_sims) != 0:
                #self.logger.experiment.add_histogram('source_anchor, true positive sims',
                #                                     true_positives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('source_anchor, true positive sims, max',
                                                  true_positives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('source_anchor, true positive sims, mean',
                                                  true_positives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'source_anchor, true positive sims, anchor {y}',
                #                                     true_positives_sims,
                #                                     self.global_step)

        elif anchor_type == 'target':
            # The anchor is from target, therefore its label may be incorrect.
            # Having a source batch, we'll check how much samples are of the same actual class
            # as target anchor
            x, _, y_real = anchor
            neg_x, neg_y, _ = negatives
            pos_x, pos_y, _ = positives

            false_negatives_sims = neg_x[neg_y == y_real]
            if len(false_negatives_sims) != 0:
                #self.logger.experiment.add_histogram('target_anchor, false negative sims',
                #                                     false_negatives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('target_anchor, false negative sims, max',
                                                  false_negatives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('target_anchor, false negative sims, mean',
                                                  false_negatives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'target_anchor, false negative sims, anchor {y_real}',
                #                                     false_negatives_sims,
                #                                     self.global_step)

            true_negatives_sims = neg_x[neg_y != y_real]
            if len(true_negatives_sims) != 0:
                #self.logger.experiment.add_histogram('target_anchor, true negative sims',
                #                                     true_negatives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('target_anchor, true negative sims, max',
                                                  true_negatives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('target_anchor, true negative sims, mean',
                                                  true_negatives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'target_anchor, true negative sims, anchor {y_real}',
                #                                     true_negatives_sims,
                #                                     self.global_step)

            false_positives_sims = pos_x[pos_y != y_real]
            if len(false_positives_sims) != 0:
                #self.logger.experiment.add_histogram('target_anchor, false positive sims',
                #                                     false_positives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('target_anchor, false positive sims, max',
                                                  false_positives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('target_anchor, false positive sims, mean',
                                                  false_positives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'target_anchor, false positive sims, anchor {y_real}',
                #                                     false_positives_sims,
                #                                     self.global_step)

            true_positives_sims = pos_x[pos_y == y_real]
            if len(true_positives_sims) != 0:
                #self.logger.experiment.add_histogram('target_anchor, true positive sims',
                #                                     true_positives_sims,
                #                                     self.global_step)
                self.logger.experiment.add_scalar('target_anchor, true positive sims, max',
                                                  true_positives_sims.max(),
                                                  self.global_step)
                self.logger.experiment.add_scalar('target_anchor, true positive sims, mean',
                                                  true_positives_sims.mean(),
                                                  self.global_step)
                #self.logger.experiment.add_histogram(f'target_anchor, true positive sims, anchor {y_real}',
                #                                     true_positives_sims,
                #                                     self.global_step)

        else:
            raise Exception(f"Wrong anchor type: {anchor_type}")

    def _filter_negative_samples(self, negatives_sims):
        """
        Filter out negative samples according to negative sampling strategy and threshold.
        """

        if self.negative_sampling is None:
            return negatives_sims

        elif self.negative_sampling == 'soft':
            indices = negatives_sims < self.explicit_negative_sampling_threshold
            return negatives_sims[indices]

        elif self.negative_sampling == 'hard':
            indices = negatives_sims > self.explicit_negative_sampling_threshold
            return negatives_sims[indices]

        elif self.negative_sampling == 'random':
            num_negs = torch.sum(negatives_sims > self.explicit_negative_sampling_threshold)
            indices = torch.randperm(len(negatives_sims))[:num_negs]

            return negatives_sims[indices]
        else:
            raise Exception(f"Wrong negative sampling option {negative_sampling}. Available options are: {negative_sampling_options}.")

    def contrastive_step(self, anchors_batch, other_batch, anchor_type):
        other_feat, other_y, other_y_real = other_batch

        contrastive_loss = 0
        for feat, y, y_real in zip(*anchors_batch):
            same_class_indices = other_y == y
            if not same_class_indices.any():
                continue

            positives = other_feat[same_class_indices]
            negatives = other_feat[~same_class_indices]

            positives_sims = positives @ feat
            positives_exp = torch.exp(positives_sims / self.tau)
            negatives_sims = negatives @ feat
#             self.analyze_negative_samples((feat, y, y_real),
#                                           (negatives_sims, other_y[~same_class_indices], other_y_real[~same_class_indices]),
#                                           (positives_sims, other_y[same_class_indices], other_y_real[same_class_indices]),
#                                           anchor_type)

            # Explicit negative sampling
            negatives_sims = self._filter_negative_samples(negatives_sims)
            negatives_exp = torch.exp(negatives_sims / self.tau)

            logit = positives_exp / (negatives_exp.sum() + positives_exp.sum())
            log = torch.log(logit)
            sum_over_all_positives = torch.nanmean(log)

            if not sum_over_all_positives.isnan():
                contrastive_loss -= sum_over_all_positives

        return contrastive_loss

    def split_batch_in_two(self, batch):
        (x, y, y_real) = batch
        half_batch_len = len(x) // 2
        x1 = x[:half_batch_len]
        y1 = y[:half_batch_len]
        y_real1 = y_real[:half_batch_len]
        x2 = x[half_batch_len:]
        y2 = y[half_batch_len:]
        y_real2 = y_real[half_batch_len:]

        assert abs(len(x1) - len(x2)) <= 1, f'{abs(len(x1) - len(x2))}'

        return (x1, y1, y_real1), (x2, y2, y_real2)

    def compute_losses(self, batch):
        source_for_classification, (source_x, source_y, source_y_real) = self.split_batch_in_two(batch['source'])
        assert torch.all(source_y == source_y_real), "y != y_real in training step"

        classification_loss = self.classification_step(source_for_classification)

        if self.pretrain_num_epochs <= self.current_epoch:
            logger.info("Do contrastive step")
            target_x, target_y, target_y_real = batch['target']

            source_features = self.feature_extractor(source_x, 0)
            target_features = self.feature_extractor(target_x, 1)
            contrastive_target_anchor = self.contrastive_step(
                (target_features, target_y, target_y_real),
                (source_features, source_y, source_y_real),
                'target'
            )
            contrastive_source_anchor = self.contrastive_step(
                (source_features, source_y, source_y_real),
                (target_features, target_y, target_y_real),
                'source'
            )
            contrastive_loss = contrastive_target_anchor + contrastive_source_anchor

        else:
            logger.info("Don't do contrastive step")
            contrastive_loss = 0

        return classification_loss, contrastive_loss

    def extract_gradients(self):
        grads = []
        for i, (name, param) in enumerate(self.feature_extractor.named_parameters()):
            grads.append(param.grad)

        for i, (name, param) in enumerate(self.classification_head.named_parameters()):
            grads.append(param.grad)

        return grads

    def sum_gradients(self, grads1, grads2):
        grads = []
        for grad1, grad2 in zip(grads1, grads2):
            if grad1 is None and grad2 is None:
                grads.append(None)
            # why there can be a None value in one grad but not in the other?
            # These are the gradients of DSBN. Classification doesn't use target-specific BN, so no gradients will be there.
            elif grad1 is None or grad2 is None:
                if grad1 is not None:
                    grads.append(grad1)
                elif grad2 is not None:
                    grads.append(grad2)

            else:
                grads.append(grad1 + grad2)

        return grads

    def set_gradients(self, grads):
        for i, (param, grad) in enumerate(zip(self.feature_extractor.parameters(), grads)):
            param.grad = grad

        for param, grad in zip(self.classification_head.parameters(), grads[i + 1:]):
            param.grad = grad

    def log_grad_norm(self, grads, name):
        nonnan_grads = list(map(lambda x: x.flatten(), filter(lambda x: x is not None, grads)))

        grad_norm = torch.hstack(nonnan_grads).norm(2).detach()
        self.logger.experiment.add_scalar(f'{name} loss grad norm', grad_norm, self.global_step)

    def training_step(self, batch):
        classification_loss, contrastive_loss = self.compute_losses(batch)
        contrastive_loss *= self.lmbda
        train_loss = classification_loss + contrastive_loss

        if self.track_grad_norm:
            opt = self.optimizers()
            sch = self.lr_schedulers()

            # Calculate gradient norms for each loss separately
            opt.zero_grad()
            if float != type(contrastive_loss):
                self.manual_backward(contrastive_loss, retain_graph=True)
                with torch.no_grad():
                    grads2 = self.extract_gradients()
                    self.log_grad_norm(grads2, "Contrastive")
            else:
                self.logger.experiment.add_scalar(f'Contrastive loss grad norm', 0, self.global_step)

            opt.zero_grad()
            self.manual_backward(classification_loss, retain_graph=True)
            with torch.no_grad():
                grads1 = self.extract_gradients()
                self.log_grad_norm(grads1, "Classification")

    #        sum_grads = self.sum_gradients(grads1, grads2)
    #        self.log_grad_norm(grads2, "Total Test")

            # Calculate gradient on a combined loss
            opt.zero_grad()
            self.manual_backward(train_loss)
            with torch.no_grad():
                grads = self.extract_gradients()
                self.log_grad_norm(grads, "Total")

            # Make a step
            self.clip_gradients(opt, gradient_clip_val=self.grad_clip, gradient_clip_algorithm="norm")
            opt.step()

            # Learning rate scheduler step
            if self.trainer.is_last_batch:
                sch.step()

        self.log_dict({
            "classification_loss": classification_loss,
            "contrastive_loss": contrastive_loss,
            "train_loss": train_loss
        }, on_epoch=True, on_step=False)

        return train_loss

    def val_metrics(self, pred, y, prefix):
        # TODO: for optimization may need to first calculate tp, tn, fp, fn
        accuracy = self.accuracy_metric(pred, y)
        #precision = self.precision_metric(pred, y)
        #recall = self.recall_metric(pred, y)

        log_dict = {}
        # for i, class_name in enumerate(self.class_names):
        #     log_dict[f'{prefix}_accuracy_{class_name}'] = accuracy[i]
        #     log_dict[f'{prefix}_precision_{class_name}'] = precision[i]
        #     log_dict[f'{prefix}_recall_{class_name}'] = recall[i]

        log_dict[f'{prefix}_accuracy'] = torch.nanmean(accuracy)
        #log_dict[f'{prefix}_precision'] = torch.nanmean(precision)
        #log_dict[f'{prefix}_recall'] = torch.nanmean(recall)

        return log_dict

    def validation_step(self, batch, batch_idx, dataloader_idx):
        def val_helper(batch, domain_name, dsbn_index):
            x, y, y_real = batch
            assert torch.all(y == y_real), f"y != y_real in validation step ({dataloader_idx})"

            pred = self(x, dsbn_index)
            loss = self.classification_loss(pred, y)

            self.log(f"{domain_name}_val_loss", loss, on_epoch=True, on_step=False, add_dataloader_idx=False)
            self.log_dict(self.val_metrics(pred, y, domain_name), on_epoch=True, on_step=False, add_dataloader_idx=False)

        # Evaluate source accuracy
        if dataloader_idx == 0:
            val_helper(batch, 'source', 0)

        # Evaluate target accuracy
        elif dataloader_idx == 1:
            # When the model pretrains or we study no_adaptation setting,
            # weights of target-specific batch norms are not trained because no samples are passed through them
            # Also, it must be evident that 'no_adaptation' means no adaptation techniques at all, so we should remove DSBN factor from model evaluation.
            dsbn_index = int(self.pretrain_num_epochs <= self.current_epoch)
            logger.info(f"Use dsbn_index {dsbn_index} on epoch {self.current_epoch} because model is pretrained for {self.pretrain_num_epochs} epochs")

            val_helper(batch, 'target', dsbn_index)

        elif dataloader_idx not in [0, 1]:
            raise Exception(f'weird dataloader num: {dataloader_idx}')

    def dataloader_target_for_clustering(self):
        return DataLoader(self.train_target_dataset,
                          batch_size=self.batch_size,
                          pin_memory=True,
                          shuffle=False,
                          num_workers=self.num_workers)

    def dataloader_source_for_centroids(self):
        return DataLoader(self.train_source_dataset,
                          batch_size=self.batch_size,
                          pin_memory=True,
                          shuffle=False,
                          num_workers=self.num_workers)

    def train_dataloader(self):
        dataloaders = {}
        dataloaders['source'] = \
                            DataLoader(self.train_source_dataset,
                                       batch_size=self.batch_size * 2,
                                       pin_memory=True,
                                       shuffle=True,
                                       num_workers=self.num_workers * 2)
        dataloaders['target'] = \
                            DataLoader(self.train_target_dataset,
                                       batch_size=self.batch_size,
                                       pin_memory=True,
                                       sampler=SubsetRandomSampler(self.valid_target_samples),
                                       num_workers=self.num_workers)

        return dataloaders

    def val_dataloader(self):
        dataloaders = []
        dataloaders.append(DataLoader(self.val_source_dataset,
                                      batch_size=self.batch_size,
                                      pin_memory=True,
                                      shuffle=False,
                                      num_workers=self.num_workers))

        dataloaders.append(DataLoader(self.val_target_dataset,
                                      batch_size=self.batch_size,
                                      pin_memory=True,
                                      shuffle=False,
                                      num_workers=self.num_workers))

        return dataloaders


import pymysql

# 打开数据库连接
db = pymysql.connect("rdsd51v1a87ixlc6uu5uo.mysql.rds.aliyuncs.com","db_mamahao_root","db_mamahao_pwd_123987","db_gd" )

# 使用cursor()方法获取操作游标
cursor = db.cursor()

fileheader='/Users/wangguannan/Downloads/单据明细'
ID="MMH2018103110000395"

header="单据编号,商品货号,商品条码,商品名称,规格,剩余库存,申请调货数量,同意调货数量"
# SQL 查询语句
sql = "SELECT id AS '单据编号',style_code AS '商品货号',barcode AS '商品条码',style_title AS '商品名称',one_value AS '规格'," \
      "p_qty AS '剩余库存',apply_from_num AS '申请调货数量' ,from_num as '同意调货数量'FROM u_stock_log_detail WHERE id = '"+ID+"'";

data=header+"\n"
try:
    # 执行SQL语句
    cursor.execute(sql)
    # 获取所有记录列表
    results = cursor.fetchall()
    for row in results:
        row=list(row)
        for j in range(len(row)):
            row[j]=str(row[j]).replace("\"","\\\"")
        data+=",".join(row)+"\n"
        print(row)
except:
    print ("Error: unable to fetch data")

# 关闭数据库连接
db.close()

fp = open(fileheader+ID+".csv",'w')
fp.write(data)
fp.close()


from sqlite3 import connect
from contextlib import contextmanager
from student import Student

""" with connect('testfiles/school.db') as conn:
    # creating a cursor object - read about cursor ????
    cur = conn.cursor()
    cur.execute('CREATE TABLE IF NOT EXISTS students(id int PRIMARY KEY, name text, cpr text)')
    cur.execute('INSERT INTO students(id, name, cpr) VALUES (1, "Claus", "223344-5566")')
    cur.execute('INSERT INTO students(id, name, cpr) VALUES (2, "Julie", "111111-1111")')
    cur.execute('INSERT INTO students(id, name, cpr) VALUES (3, "Hannah", "222222-2222")')

    for i in cur.execute('SELECT * FROM students'):
        print(i)

    cur.execute('DROP TABLE students')
 """

@contextmanager
def write_to_db(path):
        connection = connect(path)
        cursor = connection.cursor()
        cursor.execute('CREATE TABLE IF NOT EXISTS students(id int PRIMARY KEY, name text, cpr text)')
        yield connection

        cursor.execute('DROP TABLE students')
        connection.close()

students = [Student(1, 'Bob', 'CPR123'), Student(2, 'B', 'CPR123'), Student(3, 'C', 'CPR123')]

with write_to_db('./testfiles/schoo.db') as connection:
    cursor = connection.cursor()
    for student in students:
            cursor.execute(f'INSERT INTO students(id, name, cpr) VALUES ({student.id}, "{student.name}", "{student.cpr}")')

    for i in cursor.execute('SELECT * FROM students'):
        print(i)


#!/usr/bin/env python
import requests
import httplib2
import base64
import datetime
import os
import cronus.beat as beat
from cronus.timeout import timeout,TimeoutError
import ssl
import json
import sys
import logging
import time
import getopt
import thingspeak

def getSecret(name):
    path = 'run/secrets/' + name
    with open(path, 'r') as f:
        secret = f.readline()
    return secret.rstrip()

#@timeout(10)
def getSensorValue(IP):
    try:
        logger.info("Sending http request to arduino")
        response = requests.get("http://" + IP + "/")
    except requests.exceptions.RequestException as e:
        logger.error("Failed to get request from arduino: %s",e)
        return None
    else:
        logger.info("Got response from arduino")
        logger.debug("Response received: %s",response.json())
        return response
    ##    sys.exit()

#@timeout(3)
def formatMessage(arduinoResponse,api_key):
    resp = arduinoResponse.json()
    humidity = resp['variables']['humidity']
    logger.debug("Collected humidity value: %s",str(humidity))
    #message1 = base64.b64encode(str(humidity))
    data = {}
    data['api_key'] = api_key
    data['field1'] = humidity
    return data

if __name__ == "__main__":

    # Configure logging
    logger = logging.getLogger("humidityReader")
    logger.setLevel(logging.DEBUG)
    streamHandler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    streamHandler.setFormatter(formatter)
    logger.addHandler(streamHandler)
    logger.debug("Logger initialized")

    arduinoIP = getSecret("arduino1")
    api_key = getSecret("THINGSPEAK_API_KEY")
    channel_id = getSecret("THINGSPEAK_CHANNEL_ID")
    channel = thingspeak.Channel(channel_id,'api_key={api}'.format(api=api_key))

    beat.set_rate(0.016666667)

    # Publish to the same topic in a loop forever
    while beat.true():
#    while True:
        try:
            humidity = getSensorValue(arduinoIP)
        except TimeoutError:
            pass
            logger.error("Timeout error reading arduino humidity sensor")
        else:
            logger.debug("Trying to send humidity to ThingSpeak")
            channel.update(formatMessage(humidity,api_key))
        beat.sleep()


import sys
import os
import json
import pandas as pd
import matplotlib.pyplot as plt

exec(open('./../../perfline.conf').read())

class TaskInfo():
    METADATA_FILE = "perfline_metadata.json"
    RESULTS_FILE  = "s3bench_report.csv"
    def __init__(self, folder):
        self.folder = folder
        self.tid = None
        self.date = None
        self.motr = None
        self.s3server = None
        self.hare = None
        self.results = None

    def read(self):
        with open(os.path.join(self.folder, self.METADATA_FILE)) as f:
            data = json.load(f)
            self.date = data["enqueue_time"]
            self.motr = data["conf"]["custom_build"]["motr"]["branch"]
            self.s3server = data["conf"]["custom_build"]["s3server"]["branch"]
            self.hare = data["conf"]["custom_build"]["hare"]["branch"]
            self.tid = data["artifacts_dir"].split("_")[1]
            df = pd.read_csv(os.path.join(self.folder, "client", self.RESULTS_FILE))
            df = df[['numClients', 'objectSize (MB)', 'numSamples', 'Errors Count', 'Total Throughput (MB/s)', 'Errors Count.1', 'Total Throughput (MB/s).1']]
            df.rename(columns = {'Errors Count': 'Write Errors', 'Total Throughput (MB/s)': 'Write Throughput (MB/s)', 'Errors Count.1': 'Read Errors', 'Total Throughput (MB/s).1': 'Read Throughput (MB/s)'}, inplace=True)
            df['TID'] = self.tid
            df['motr'] = self.motr
            df['s3server'] = self.s3server
            df['hare'] = self.hare
            df['date'] = self.date
            self.results = df

    def get_results(self):
        return self.results

    def __str__(self):
        return "TID: {}, Date: {}, motr: {}, s3server: {}, hare: {}".format(
            self.tid, self.date, self.motr, self.s3server, self.hare)

def usage():
    use = """
fetch.py - Fetch build and performance data from list of tasks results.
Information is stored in default night-builds daemon artifacts in
form of bandwidth plots and json dumps.

Usage:
\tpython3 fetch.py "$list_of_tasks_results_dirs" main
\tpython3 fetch.py "$list_of_tasks_results_dirs" stable

for main and stable builds respectively.
    """
    print(use)

def plot_stable(df, filename, size, sessions):
    # TODO: Implement me!
    pass

def plot_main(df, filename, size, sessions):
    commit_domain = df[['motr', 's3server']].drop_duplicates()

    dots = []
    for _, row in commit_domain.iterrows():
        fd = df[(df['motr'] == row['motr']) & (df['s3server'] == row['s3server'])]
        writes = fd['Write Throughput (MB/s)'].tolist()
        reads = fd['Read Throughput (MB/s)'].tolist()

        dots.append({(str(row['motr']), str(row['s3server'])) : {'write': writes, 'read': reads}})

    plot = plt.figure(figsize=(16, 8))

    avgs_x = []
    avgs_write = []
    avgs_read = []
    for d in dots:
        x = next(iter(d))
        y1 = d[x]['write']
        y2 = d[x]['read']
        x = "motr {}\ns3 {}".format(x[0], x[1])

        plt.scatter([x]*len(y1), list(y1), color='red')
        plt.scatter([x]*len(y2), y2, color='green')

        avgs_x.append(x)
        avgs_write.append(sum(y1)/len(y1))
        avgs_read.append(sum(y2)/len(y2))

    plt.scatter(avgs_x, avgs_write, marker='X', color='black')
    plt.scatter(avgs_x, avgs_read, marker='X', color='black')

    plt.plot(avgs_x, avgs_write, color='red', label = 'Write')
    plt.plot(avgs_x, avgs_read, color='green', label = 'Read')

    plt.ylim(bottom=0.0)
    plt.xticks(rotation=45)
    plt.margins(0.5)
    plt.subplots_adjust(bottom=0.2)
    plt.grid()
    plt.title(f"Main branch throughput, {size}, {sessions} sessions")
    plt.ylabel("Throughput, MB/s")
    plt.xlabel("Motr, s3server commit IDs", fontsize=16)
    plt.legend()

    print("Will save to {}".format(filename))
    plt.savefig(filename)
    plt.close(plot)

def plot_img(df, build, filename, size, sessions):
    if build == "main":
        plot_main(df, filename, size, sessions)
    elif build == "stable":
        plot_stable(df, filename, size, sessions)

def main():
    if len(sys.argv) != 3:
        usage()
        exit(1)
    build = sys.argv[1]
    dirs = sys.argv[2].split()

    if build not in ["main", "stable"]:
        usage()
        exit(2)

    tasks = []
    for d in dirs:
        task = TaskInfo(d)
        task.read()
        tasks.append(task)

    df = pd.concat([t.get_results() for t in tasks])
    df.sort_values(by=["date"], inplace=True)

    for size in df['objectSize (MB)'].unique():
        for sessions in df['numClients'].unique():
            fd = df[(df['objectSize (MB)'] == size) & (df['numClients'] == sessions)][['date', 'TID', 'motr', 's3server', 'hare',
                                                                                'Write Errors', 'Write Throughput (MB/s)',
                                                                                'Read Errors', 'Read Throughput (MB/s)']]

            size_lookup = {
                "0.0009765625" : "1KB",
                "0.00390625"   : "4KB",
                "0.015625"     : "16KB",
                "0.0625"       : "64KB",
                "0.25"         : "256KB",
                "1.0"          : "1MB",
                "4.0"          : "4MB",
                "16.0"         : "16MB",
                "32.0"         : "32MB",
                "64.0"         : "64MB",
                "128.0"        : "128MB",
                "256.0"        : "256MB",
            }

            # Save json
            base = "_".join([size_lookup[str(size)], str(sessions)])
            filename = os.path.join(NIGHT_ARTIFACTS, build, "data", base + ".json")
            print("Will save to {}".format(filename))
            fd.to_json(filename, orient="split")

            # Save png
            filename = os.path.join(NIGHT_ARTIFACTS, build, "img", base + ".png")
            plot_img(fd, build, filename, size_lookup[str(size)], str(sessions))

if __name__=="__main__":
    main()


#! /usr/bin/env python3

import argparse
import numpy as np
from datetime import datetime, timedelta
import pandas as pd
import numpy as np
import xarray as xr
import netCDF4 as nc
import os

def writeRstCICE(fileCICE, pathCICE, data, var, defaultExp):
   dsCICE=xr.open_dataset(pathCICE+'/'+fileCICE)
   if (var == "utic"):
       id_var="strwvx"
   elif (var == "vtic"):
       id_var="strwvy"
   elif (var == 'efreq'):
       id_var='efreq'
   else:
       print("Unknown WW3 variable")
#   data=np.ones((data.shape[0], data.shape[1]))*5
#   data1=np.zeros((data.shape[0], data.shape[1]))
   #Only zonal stress.
   if defaultExp == "wimgx3" or defaultExp == "wimgx1" or defaultExp == "wimtx1":
       if (id_var == 'strwvx'):
           dsCICE[id_var]=(['lat', 'lon'], data)
       elif (id_var == 'strwvy'):
           dsCICE[id_var]=(['lat', 'lon'], data)
       elif (id_var == 'efreq'):
           dsCICE[id_var]=(['f', 'lat', 'lon'], data)
   elif defaultExp == "wim2p5":
       if (id_var == 'strwvx'):
           dsCICE[id_var]=(['y', 'x'], data)
       elif (id_var == 'strwvy'):
           dsCICE[id_var]=(['y', 'x'], data)
       elif (id_var == 'efreq'):
           dsCICE[id_var]=(['f', 'y', 'x'], data)

   os.system("mv "+pathCICE+'/'+fileCICE+" "+pathCICE+"/temp")
   dsCICE.to_netcdf(pathCICE+'/'+fileCICE)
   print(id_var+" has been added to "+pathCICE+'/'+fileCICE)

def get_geomWW3(path, file, defaultExp):
    '''
    This function reads the ni, nj, tlat, and tlon variables from a netcdf file
    '''
    fid = nc.Dataset("{}/{}".format(path, file), 'r')
    if defaultExp == "wim2p5":
        tlat = fid.variables['y'][:]
        tlon = fid.variables['x'][:]
        ni = fid.dimensions['y'].size #ni is for lat, nj for lon
        nj = fid.dimensions['x'].size
    elif defaultExp == "wimgx3" or defaultExp == "wimgx1" or defaultExp == "wimtx1":
        tlat = fid.variables['latitude'][:]
        tlon = fid.variables['longitude'][:]
        ni = fid.dimensions['lon'].size #ni is for lat, nj for lon
        nj = fid.dimensions['lat'].size
    return nj, ni, tlat, tlon

def read_stressWW3(path_a, files_a, var, nj, ni):
    '''
    Read the baseline and test data for sea ice thickness.  The calculate
    the difference for all locations where sea ice thickness is greater
    than 0.01 meters.
    '''
    def fill_data_array(path, files, nj, ni):
        '''Function to fill the data arrays'''
        # Initialize the data array
        data = np.zeros((nj, ni),dtype=np.float32)
        # Read in the data
        fname=files[0]
        nfid = nc.Dataset("{}/{}".format(path, fname), 'r')
        fill_value = nfid.variables[var]._FillValue
        data[:, :] = nfid.variables[var][:]
        nfid.close()
        data[data == fill_value] = 0.0

        return data

    data_a = fill_data_array(path_a, files_a, nj, ni)

    return data_a

def read_specWW3(path_a, files_a, var, nj, ni, nf):
    '''
    Read the baseline and test data for sea ice thickness.  The calculate
    the difference for all locations where sea ice thickness is greater
    than 0.01 meters.
    '''
    def fill_data_array(path, files, nj, ni):
        '''Function to fill the data arrays'''
        # Initialize the data array
        data = np.zeros((nf, nj, ni),dtype=np.float32)
        # Read in the data
        fname=files[0]
        nfid = nc.Dataset("{}/{}".format(path, fname), 'r')
        fill_value = nfid.variables[var]._FillValue
        data[:, :, :] = nfid.variables[var][:]
        nfid.close()
        data[data == fill_value] = 0.0

        return data

    data_a = fill_data_array(path_a, files_a, nj, ni)

    return data_a

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("case", help="Name of the case (e.g. case01).")
    parser.add_argument("repOutW3", help="Path for WW3 output file.")
    parser.add_argument("fileOutW3", help="Name of WW3 output file.")
    parser.add_argument("repRstCI", help="Path for CICE restart file.")
    parser.add_argument("fileRstCI", help="Path for CICE restart file.")
    parser.add_argument("defaultExp", help="wim2p5, wimgx3, wimgx1, wimtx1")
    args = parser.parse_args()

    #Define variables
    case=args.case
    repOutW3=args.repOutW3
    repRstCI=args.repRstCI
    defaultExp=args.defaultExp
    fileOutW3=args.fileOutW3
    fileRstCI=args.fileRstCI
    nlon, nlat, t_lat, t_lon = get_geomWW3(repOutW3, fileOutW3, defaultExp)
#    listVar=['utic', 'vtic', 'efreq']
    listVar=['utic', 'vtic']
 #   fileOutSpec="ww3.2005-01-01-03600_efreq.nc"
 #   fileOutW3="ww3.2005-01-01-03600.nc"
    fileOutSpec=fileOutW3[:-3]+"_efreq.nc"
    print("File :"+repOutW3+"/"+fileOutW3+" is read")
    for var in listVar:
       if var == 'efreq':
#          varWW3=read_specWW3(repOutW3, ['ww3.2005-01-01-07200_efreq.nc'], var, nlon, nlat, 20)
           varWW3=read_specWW3(repOutW3, [fileOutSpec], var, nlon, nlat, 20)
       else:
           varWW3=read_stressWW3(repOutW3, [fileOutW3], var, nlon, nlat)
       writeRstCICE(fileRstCI, repRstCI, varWW3, var, defaultExp)
#Call main
if __name__ == "__main__":
    main()


import argparse

import pandas as pd
import torch
from torch_geometric.loader import DataLoader

from benchmark import UnlabeledData, Descriptors
from models import squeeze_if_needed, get_model

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('config', type=str, default='./configs/ace.yml')
    parser.add_argument('--data', metavar='DATA', type=str, default='CHEMBL214_Ki')
    parser.add_argument('--model', metavar='MODEL', type=str, default='GIN', choices=['MPNN', 'GAT', 'GCN', 'GIN'])

    parser.add_argument('--target_path', type=str, default='./CHEMBL_214')   # ./250k_zinc
    parser.add_argument('--model_path', type=str, default='./results/GIN_CHEMBL214_Ki_best_0.pt')
    args = parser.parse_args()
    algorithm = get_model(args.model)
    ckpt = torch.load(args.model_path)
    config = ckpt['config']

    target_data = UnlabeledData(args.target_path, size_limit=-1)
    if target_data.x is None:
        target_data(Descriptors.GRAPH, save_mode=False)
    x_target = target_data.x
    loader = DataLoader(x_target, batch_size=config.train.batch + 1 if len(x_target) % config.train.batch == 1 else config.train.batch, shuffle=False)
    print(f'Model weight: {args.model_path} | Unlabeled Size: {len(x_target)}')

    algorithm = get_model(args.model)

    model = algorithm(mean=ckpt['mean'], mad=ckpt['mad'], config=config, **config.model)
    model.model.load_state_dict(ckpt['model'])
    model.critic.load_state_dict(ckpt['critic'])

    y_pred, p_pred = [], []
    model.model.eval()
    model.critic.eval()
    with torch.no_grad():
        for batch in loader:
            batch.to(model.device)
            y_hat = model.model(batch.x.float(), batch.edge_index, batch.edge_attr.float(), batch.batch).detach() * ckpt['mad'] + ckpt['mean']

            # assume some sort of loss
            p = model.critic(batch.x.float(), batch.edge_index, batch.edge_attr.float(), batch.batch, y_hat.detach().clone(), torch.ones_like(y_hat).squeeze(-1))

            y_hat = squeeze_if_needed(y_hat).tolist()
            p = squeeze_if_needed(p).tolist()
            if type(y_hat) is list:
                y_pred.extend(y_hat)
            else:
                y_pred.append(y_hat)
            if type(p) is list:
                p_pred.extend(p)
            else:
                p_pred.append(p)

    df = pd.DataFrame({'smiles': target_data.smiles, 'Ki': [10 ** (-x) / 5 for x in y_pred], 'confidence': p_pred})  #
    df.to_csv(f'./{args.target_path}_inference.csv')


#!/usr/bin/python3
# Copyright (c) 2022 Innodisk Crop.
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT

import os
import argparse
import time
import numpy as np
import queue
import logging
import datetime
import sys

from mod.predictor import PREDICTOR
from mod.util import open_json

DISPLAY_CARD_PATH = '/dev/dri/by-path/platform-fd4a0000.zynqmp-display-card'

version = "1.0.0"
date = datetime.date.today()

CFG     = 'config.json'
DISPLAY = "DISPLAY"
WIDTH   = "WIDTH"
HEIGHT  = "HEIGHT"
divider = '------------------------------------'

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('-c', '--camera', type=str, help='Camera type, default is /dev/video0')
    ap.add_argument('-i', '--image' , type=str, help='Path to a image which you would like to inference.')
    ap.add_argument('-t', '--target', type=str, help='Output type, default is dp')
    ap.add_argument('-v', '--video' , type=str, help='Path to a video which you would like to inference.')
    ap.add_argument('-x', '--xmodel', type=str, default='yolo', help='Type of xmodel, default is yolo')
    ap.add_argument('-l', '--lpr'   , type=str, help='Enable LPR mode. This is base on yolo object detection.')

    args = ap.parse_args()
    cfg = open_json(CFG)
    pred = PREDICTOR(args, cfg)

    logging.basicConfig(level=logging.INFO)

    logging.info(divider)
    logging.info(" Command line options:")
    logging.info(" Version: {}".format(version))
    logging.info(" Date:    {}".format(date))

    ''' Select Input '''
    # if args.camera == 'g4':
    #     logging.info(' --input     : {}'.format('g4'))
    #     pred.get_frame = pred.g4cam_get

    if args.camera:
        if (args.camera.isdigit()):
            logging.info(' --input     : {}'.format('web-cam'))
            pred.get_frame = pred.cam_get

        else:
            print("string, please input digital number")
            return

    elif args.image:
        if os.path.isfile(args.image):
            logging.info(' --input     : {}'.format('image'))
            pred.get_frame = pred.image_get

        else:
            print("Could not find the file {}.".format(args.image))
            return

    elif args.video:
        if os.path.isfile(args.video):
            logging.info(' --input     : {}'.format('video'))
            pred.get_frame = pred.video_get

        else:
            print("Could not find the file {}.".format(args.image))
            return

    ''' Select Xmodel '''
    if args.xmodel == 'cnn':
        logging.info(' --model     : {}'.format('cnn'))
        pred.init_model = pred.init_cnn
        pred.run_model = pred.run_cnn

    else:
        logging.info(' --model     : {}'.format('yolo'))
        pred.init_model = pred.init_yolo

        if args.lpr:
            logging.info(' --lpr     : {}'.format('enable'))
            pred.run_model = pred.run_yolo_lpr
        else:
            pred.run_model = pred.run_yolo

    ''' Select Output '''
    if args.target == 'dp':
        if not os.path.exists(DISPLAY_CARD_PATH):
            logging.info('Error: zynqmp-display device is not ready.')
            return

        ''' Resolution check '''
        width = int(pred.cfg[DISPLAY][WIDTH])
        height = int(pred.cfg[DISPLAY][HEIGHT])

        resolution = "{}x{}".format(width, height)
        all_res = os.popen("modetest -M xlnx -c| awk '/name refresh/ {f=1;next}  /props:/{f=0;} f{print $1 \"@\" $2}'").read()

        if all_res.find(resolution) == -1:
            os.environ["DISPLAY"] = ":0"

        logging.info(' --output    : {}'.format('dp'))
        pred.output = pred.dp_out

    elif args.target == 'image':
        logging.info(' --output    : {}'.format('image'))
        pred.output = pred.image_out

    elif args.target == 'video':
        logging.info(' --output    : {}'.format('video'))
        pred.output = pred.video_out

    pred.predict()

if __name__ == '__main__':
    main()


import re  #importar libreria re
from tkinter import EW #importar libreria tkinter
from django.shortcuts import redirect, render
from app_gestion.models import Datos_vacuna
from app_gestion.forms import Datos_vacuna_Form

def index(request):
    Datos_vacunas = Datos_vacuna.objects.all()
    return render(request, '/front/Informacion/informacion.html', {'Datos_vacuna': Datos_vacunas})

def eliminar(request, rut):
    remover = Datos_vacuna.objects.get(rut=rut)
    remover.delete()
    return redirect('informacion')

def registrar(request):
    rut = request.POST.get('rut')
    nombre = request.POST.get('nombre')
    apellido_mat = request.POST.get('apellido_mat')
    apellido_pat = request.POST.get('apellido_pat')
    edad = request.POST.get('edad')
    vacuna = request.POST.get('vacuna')
    tipo_vacuna = request.POST.get('Tipo_Vacuna')
    fecha = request.POST.get('fecha')
    registro=Datos_vacuna.objects.create(rut=rut, nombre=nombre, apellido_mat=apellido_mat, apellido_pat=apellido_pat, edad=edad, vacuna=vacuna, fecha=fecha)
    return redirect('informacion')


#!/usr/bin/env python
import nltk
import os
import time

import nltk

from neo4j import GraphDatabase

# uri = "bolt://localhost:7687"
uri = os.environ.get('NEO_URL', "bolt://neo:7687")
DEBUG = os.environ.get('DEBUG', False)

GRAMMAR = r"""
  NP: {<CD|DT|PP\$>?<JJ[RS]*|PRP\$*>*<NN.*>+} # Chunk sequences of DT, JJ, NN, chink out VPs
  PP: {<IN><PR.*>*<N.*>}                           # Chunk prepositions followed by NP
  XPP: {<IN><.*>+<N.*>}                           # Chunk prepositions followed by NP
  VP: {<VB(?!P).*>+<RB>*(<PRP><JJ>)*}             # Chunk verbs and their arguments
  NOUNANDVERB: {<NP><VP>}                  # Chunk NP to VP
  VERBANDPREP: {<VP><PP>}
  GOODNOUNSANDVERBS: {<NN.*><VB.*>+}
  SENTENCE: {<NOUNANDVERB><PP>}
  """

def connect_to_neo(uri=""):
    for i in range(1,60):
        while True:
            try:
                driver = GraphDatabase.driver(uri, connection_timeout=120)
            except Exception as e:
                print(f"Error number {i}. {e}.")
                print(f"Error number {i} connecting to neo, sleeping for 2 seconds")
                time.sleep(2)
            break
    return driver

def get_random_phrases(session=None, p_type="" ):
    rwords = list()
    cypher = f"""MATCH NounBit=(p:Phrase)-[r:{p_type}]-() RETURN p.text, rand() as x order by x LIMIT 10"""
    words = session.run(cypher)
    for w in words:
        rwords.append(w['p.text'])
    return rwords

def filter_good_sentences(noun_phrases=[], verb_phrases=[]):
    sentences = list()
    rD = dict()
    for noun in noun_phrases:
        for verb in verb_phrases:
            sentence = " ".join([noun, verb])
            sentences.append(sentence)
    for sentence in sentences:
        tokenized = nltk.word_tokenize(sentence)
        postagged = nltk.pos_tag(tokenized)
        chunks = cp.parse(postagged)
        care_about = ['SENTENCE' ]
        for chunk_idx, chunk in enumerate(chunks.subtrees(filter=lambda t: t.label() in care_about )):
            rD[sentence] = {"chunks": chunks, "pos": postagged}
    return rD

if __name__ == "__main__":
    cp = nltk.RegexpParser(GRAMMAR)
    stemmer = nltk.stem.PorterStemmer()
    driver = connect_to_neo(uri=uri)

    noun_phrases = list()
    verb_phrases = list()

    with driver.session() as session:
        noun_phrases = get_random_phrases(session=session, p_type="NP")
        verb_phrases = get_random_phrases(session=session, p_type="VERBANDPREP")

    prototype_phrases = list()
    keep_sentences = dict()

    keep_sentences = filter_good_sentences(noun_phrases=noun_phrases, verb_phrases=verb_phrases)

    if DEBUG:
        for sentence, bits in keep_sentences.items():
            print(sentence)
            for idx, tree in enumerate(bits['chunks'].subtrees()):
                print(tree)
            print(bits['pos'])

    for sentence in keep_sentences.keys():
        print(sentence)


from django.urls import path, re_path

from . import consumers
from . import views

urlpatterns = [
    path('character/all', views.get_all_characters, name='get_all_characters'),
    path('character/<int:id>', views.get_character, name='get_character'),
    path('character/create', views.create_character, name='create_character'),
    path('character/<int:id>/update', views.update_character, name='update_character'),
    path('character/<int:id>/delete', views.delete_character, name='delete_character'),

    path('question/<int:library_id>/all', views.get_all_questions_in_library, name='get_all_questions_in_library'),
    path('question/<int:id>', views.get_question, name='get_question'),
    path('question/create', views.create_question, name='create_question'),
    path('question/<int:id>/delete', views.delete_question, name='delete_question'),
    path('question/<int:id>/update', views.update_question, name='update_question'),
    path('library/question/all', views.get_all_question_libraries, name='get_all_question_libraries'),
    path('library/question/create', views.create_question_library, name='create_question_library'),

    path('speech/<int:library_id>/all', views.get_all_speeches_in_library, name='get_all_speeches_in_library'),
    path('speech/<int:id>', views.get_speech, name='get_speech'),
    path('speech/create', views.create_speech, name='create_speech'),
    path('speech/<int:id>/delete', views.delete_speech, name='delete_speech'),
    path('speech/<int:id>/update', views.update_speech, name='update_speech'),
    path('library/speech/all', views.get_all_speech_libraries, name='get_all_speech_libraries'),
    path('library/speech/create', views.create_speech_library, name='create_speech_library'),

    path('words/<int:library_id>/all', views.get_all_words_in_library, name='get_all_words_in_library'),
    path('words/<int:id>', views.get_word, name='get_word'),
    path('words/create', views.create_word, name='create_word'),
    path('words/<int:id>/delete', views.delete_word, name='delete_word'),
    path('words/<int:id>/update', views.update_word, name='update_word'),
    path('library/words/<str:library_type>/all', views.get_all_words_libraries_by_type, name='get_all_words_libraries_by_type'),
    path('library/words/create', views.create_words_library, name='create_words_library'),

    path('lens/all', views.get_all_lenses, name='get_all_lenses'),
    path('lens/<int:id>', views.get_lens, name='get_lens'),
    path('lens/create', views.create_lens, name='create_lens'),
    path('lens/<int:id>/update', views.update_lens, name='update_lens'),
    path('lens/<int:id>/delete', views.delete_lens, name='delete_lens'),

    path('image/all', views.get_all_images, name='get_all_images'),
    path('image/create', views.create_image, name='create_image'),
    path('image/<int:image_id>/bind', views.bind_user_image, name='bind_user_image'),
    path('image/<int:image_id>/update', views.update_image, name='update_image'),
    path('image/<int:image_id>/delete', views.delete_image, name='delete_image'),

    path('environment/all', views.get_all_environments, name='get_all_environments'),
    path('environment/create', views.create_environment, name='create_environment'),
    path('environment/<int:environment_id>/bind', views.bind_user_environment, name='bind_user_environment'),
    path('environment/<int:environment_id>/update', views.update_environment, name='update_environment'),
    path('environment/<int:environment_id>/delete', views.delete_environment, name='delete_environment'),

    path('get_alipay_url_image/<int:image_id>', views.get_alipay_payment_url_image),
    path('get_alipay_url_environment/<int:environment_id>', views.get_alipay_payment_url_environment),

    path('live_config', views.get_live_config, name='get_live_config'),
    path('live_config/update', views.update_live_config, name='update_live_config'),

]

websocket_urlpatterns = [
    re_path(r'(?P<mode>chat|speech)/generate$', consumers.AiGeneratorWsConsumer.as_asgi()),
]


import os
from mock import patch, AsyncMock
import pytest
from httpx import AsyncClient
from src.main.app import app
from src.tests.controller.view.carrer import CarrerMother

@pytest.fixture()
def auth_header():
    os.environ["ADMIN_AUTH"] = "mock_auth"
    return {"admin-auth": "mock_auth"}

@pytest.mark.anyio
@patch("src.main.controller.carrer.CarrerRepository.create")
async def test_create(repository: AsyncMock, auth_header: dict):
    carrers = CarrerMother.create_many()
    async with AsyncClient(app=app, base_url="http://test") as client:
        response = await client.post(
            "/carrers", json=carrers.model_dump(), headers=auth_header
        )
    repository.assert_awaited_once_with(carrers)
    assert response.status_code == 200

@pytest.mark.anyio
@patch("src.main.controller.carrer.CarrerRepository.get_all")
async def test_get(repository: AsyncMock, auth_header: dict):
    carrers = CarrerMother.create_many_paginated()
    async with AsyncClient(app=app, base_url="http://test") as client:
        repository.return_value = carrers
        response = await client.get("/carrers", headers=auth_header)
    repository.assert_awaited_once()
    assert response.status_code == 200
    assert response.json()["result"] == carrers.model_dump()

@pytest.mark.anyio
@patch("src.main.controller.carrer.CarrerRepository.delete")
async def test_delete(repository: AsyncMock, auth_header: dict):
    id = 1
    async with AsyncClient(app=app, base_url="http://test") as client:
        response = await client.delete(f"/carrers/{id}", headers=auth_header)
    repository.assert_awaited_once_with(id)
    assert response.status_code == 200


import copy
import time
from abc import abstractmethod
from queue import Empty

import cv2
import numpy as np
import torch
from PIL import ImageFont, Image, ImageDraw
from PyQt5.QtGui import QPixmap, QImage

from model.core.base_module import BaseModule, TASK_DATA_OK, DictData
from utils.vis import draw_keypoints136

box_color = (0, 255, 0)  #
cheating_box_color = (0, 0, 255)
draw_keypoints_default = False

# 绘制图片
def draw_frame(data, draw_keypoints=draw_keypoints_default, fps=-1):
    frame = data.frame.copy()  # 图片赋值给frame
    pred = data.detections  # 将data中处理后的数据赋值给pred
    preds_kps = data.keypoints  # 将data中的关键点赋值给preds_kps
    preds_scores = data.keypoints_scores  # 将data中的关键点成绩赋值给preds_scores
    if pred.shape[0] > 0:
        # 绘制骨骼关键点
        if draw_keypoints and preds_kps is not None:
            draw_keypoints136(frame, preds_kps, preds_scores)
        # 绘制目标检测框和动作分类
        frame_pil = Image.fromarray(frame)
        draw = ImageDraw.Draw(frame_pil)
        for det, class_prob, best_pred in zip(pred, data.classes_probs, data.best_preds):
            det = det.to(torch.int)  # 转换类型
            class_name = data.classes_names[best_pred]  # 选择类名
            show_text = f"{class_name}"  # 设置要展示的类名
            show_color = box_color if best_pred == 0 else cheating_box_color  # 设置要展示颜色
            draw.rectangle((det[0], det[1], det[2], det[3]), outline=show_color, width=2)  # 绘制矩形
            # 文字
            fontText = ImageFont.truetype("resource/font/NotoSansCJKkr-Black.otf",
                                          int(40 * (min(det[2] - det[0], det[3] - det[1])) / 200),
                                          encoding="utf-8")  # 加载文字
            draw.text((det[0], det[1]), show_text, show_color, font=fontText)  # 在给定位置绘制字符串
        frame = np.asarray(frame_pil)
        # 头部姿态估计轴
        for (r, t) in data.head_pose:
            data.draw_axis(frame, r, t)
    # 绘制fps
    cv2.putText(frame, "FPS: %.2f" % fps, (0, 52), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255))
    data.frame_anno = frame  # 保存绘制过的图像

# 绘制模块
class DrawModule(BaseModule):
    def __init__(self):
        super(DrawModule, self).__init__()
        self.last_time = time.time()  # 最终时间

    def process_data(self, data):
        # 数据预处理
        print("显示图片")
        current_time = time.time()  # 当前时间
        fps = 1 / (current_time - self.last_time)  # fps计算
        frame = data.frame  # 框
        pred = data.detections
        preds_kps = data.keypoints
        preds_scores = data.keypoints_scores
        for det in pred:
            show_text = "person: %.2f" % det[4]
            cv2.rectangle(frame, (det[0], det[1]), (det[2], det[3]), box_color, 2)  # 绘制矩形
            cv2.putText(frame, show_text,  # 绘制文字
                        (det[0], det[1]),
                        cv2.FONT_HERSHEY_COMPLEX,
                        float((det[2] - det[0]) / 200),
                        box_color)
        if preds_kps is not None:
            draw_keypoints136(frame, preds_kps, preds_scores)
        # 记录fps
        cv2.putText(frame, "FPS: %.2f" % fps, (0, 52), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255))
        # 显示图像
        cv2.imshow("yolov5", frame)
        cv2.waitKey(40)
        self.last_time = current_time
        return TASK_DATA_OK

    def open(self):
        super(DrawModule, self).open()
        pass

# 保存模块
class FrameDataSaveModule(BaseModule):
    def __init__(self, app):
        super(FrameDataSaveModule, self).__init__()
        self.last_time = time.time()
        self.app = app

    def process_data(self, data):
        current_time = time.time()
        fps = 1 / (current_time - self.last_time)
        frame = data.frame
        pred = data.detections
        preds_kps = data.keypoints
        preds_scores = data.keypoints_scores
        for det in pred:
            show_text = "person: %.2f" % det[4]
            cv2.rectangle(frame, (det[0], det[1]), (det[2], det[3]), box_color, 2)
            cv2.putText(frame, show_text,
                        (det[0], det[1]),
                        cv2.FONT_HERSHEY_COMPLEX,
                        float((det[2] - det[0]) / 200),
                        box_color)
        if preds_kps is not None:
            draw_keypoints136(frame, preds_kps, preds_scores)
        # 记录fps
        cv2.putText(frame, "FPS: %.2f" % fps, (0, 52), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 255))
        self.app.video_screen.setPixmap(self.cvImg2qtPixmap(frame))
        time.sleep(0.04)
        self.last_time = current_time
        return TASK_DATA_OK

    @staticmethod
    def cvImg2qtPixmap(frame):
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        image_height, image_width, image_depth = frame.shape
        frame = QImage(frame.data, image_width, image_height,  # 创建QImage格式的图像，并读入图像信息
                       image_width * image_depth,
                       QImage.Format_RGB888)
        return QPixmap.fromImage(frame)

    def open(self):
        super(FrameDataSaveModule, self).open()
        pass

# 数据传输模块
class DataDealerModule(BaseModule):
    def __init__(self, push_frame_func, interval=0.06, skippable=False):
        super(DataDealerModule, self).__init__(skippable=skippable)
        self.last_time = time.time()
        self.push_frame_func = push_frame_func
        self.last_data = None
        self.interval = interval  # 间隔
        self.size_waiting = True
        self.queue_threshold = 10  # 队列的阈值

    # 跳过大量数据
    @abstractmethod
    def deal_skipped_data(self, data: DictData, last_data: DictData) -> DictData:
        pass

    # 绘制框
    @abstractmethod
    def draw_frame(self, data, fps):
        pass

    # 数据预处理
    def process_data(self, data):
        # hasattr() 函数用于判断对象是否包含对应的属性。
        if hasattr(data, 'skipped') and self.last_data is not None:
            data = self.deal_skipped_data(data, copy.copy(self.last_data))
        else:
            self.last_data = data
        current_time = time.time()
        interval = (current_time - self.last_time)
        fps = 1 / interval
        data.fps = fps
        self.draw_frame(data, fps=fps)
        data.interval = interval
        self.last_time = current_time  # 更新时间
        self.push_frame_func(data)
        if hasattr(data, 'source_fps'):
            time.sleep(1 / data.source_fps * (1 + self.self_balance_factor()))
        else:
            time.sleep(self.interval)
        return TASK_DATA_OK

    # 平衡因子
    def self_balance_factor(self):
        factor = max(-0.999, (self.queue.qsize() / 20 - 0.5) / -0.5)
        # print(factor)
        return factor

    # 产生工作数据
    def product_task_data(self):
        # print(self.queue.qsize(), self.size_waiting)
        if self.queue.qsize() == 0:
            self.size_waiting = True
        if self.queue.qsize() > self.queue_threshold or not self.size_waiting:
            self.size_waiting = False
            try:
                task_data = self.queue.get(block=True, timeout=1)
                return task_data
            except Empty:
                return self.ignore_task_data
        else:
            time.sleep(1)
            return self.ignore_task_data

    # 存入工作数据
    def put_task_data(self, task_data):
        self.queue.put(task_data)

    # 打开
    def open(self):
        super(DataDealerModule, self).open()
        pass

# 作弊检测模块
class CheatingDetectionVisModule(DataDealerModule):

    def __init__(self, push_frame_func, interval=0.06, skippable=False):
        super(CheatingDetectionVisModule, self).__init__(push_frame_func, interval, skippable)

    # 跳过大量数据
    def deal_skipped_data(self, data: DictData, last_data: DictData) -> DictData:
        frame = data.frame  # 帧图片
        data = last_data  # 最终数据
        data.skipped = None  # 跳过
        data.frame = frame  # 帧图片
        # 返回一个和源张量同shape、dtype和device的张量，与源张量不共享数据内存，但提供梯度的回溯
        data.detections = data.detections.clone()
        # 添加抖动 返回一个张量，其大小与填充区间上均匀分布的随机数的张量相同
        data.detections[:, :4] += torch.rand_like(data.detections[:, :4]) * 3
        return data

    # 绘制框
    def draw_frame(self, data, fps):
        draw_frame(data, fps=fps)


from django.urls import path, include
from myacc import views

urlpatterns = [
    path('', views.index),
    path('insert/', views.insert),
    path('view/', views.view),
    path('update/', views.update),
    path('delete/', views.delete),
#    path('<str:acc_type>/', views.index),
]


#!/usr/bin/env python
# coding: utf-8

# CONVERT DFA TO REGEX

import json
import sys

with open(sys.argv[1], 'r') as f:
    DFA = json.load(f)

def join(string1, string2):
    if string1 == '$':
        return string2
    if string2 == '$':
        return string1
    return string1 + string2

# remove dead states

def resolve_dead(delta):
    check = {}
    for state in DFA['states']:
        check.update({state: False})
    for state in DFA['start_states']:
        check[state] = True
    for edge in delta:
        check[edge[2]] = True
    return [edge for edge in delta if check[edge[0]]], [state for state in check if check[state]]

# simplifty parallel edges

def resolve_parallel(delta):
    hist = []
    n = len(delta)
    for i in range(n):
        for j in range(i+1, n):
            if delta[i][0] == delta[j][0] and delta[i][2] == delta[j][2]:
                new_edge = [
                    delta[i][0], '(' + delta[i][1] + '+' + delta[j][1] + ')', delta[i][2]]
                delta.remove(delta[j])
                delta.append(new_edge)
                hist.append(delta[i])
                i += 1
    for old_edge in hist:
        if old_edge in delta:
            delta.remove(old_edge)
    return delta

# removing self-loops

def resolve_selfloops(delta):
    loops = []
    for edge in delta[:]:
        if edge[0] == edge[2]:
            loops.append(edge)
            delta.remove(edge)
    for loop in loops:
        for i, edge in enumerate(delta):
            if loop[0] == edge[0]:
                delta[i][1] = join('(' + loop[1] + ')*', edge[1])
    return delta

def remove_state(state, delta):
    incoming = [edge for edge in delta if edge[2] == state]
    outgoing = [edge for edge in delta if edge[0] == state]
    for edge in (incoming + outgoing):
        delta.remove(edge)
    for inedge in incoming:
        for outedge in outgoing:
            edge = [inedge[0], join(inedge[1], outedge[1]), outedge[2]]
            delta.append(edge)
    delta = resolve_parallel(delta)
    delta = resolve_selfloops(delta)
    return delta

if __name__ == '__main__':
    delta = DFA['transition_function'].copy()

    # STEP ZERO: remove dead states

    delta, valid_states = resolve_dead(delta)

    # STEP ONE: NEW INITIAL AND FINAL STATES

    start = 'Qs'
    final = 'Qf'

    for s in DFA['start_states']:
        delta.append([start, '$', s])
    for f in DFA['final_states']:
        delta.append([f, '$', final])

    # STEP TWO: simplify parallel edges

    delta = resolve_parallel(delta)

    # STEP THREE: removing self-loops

    delta = resolve_selfloops(delta)

    for state in valid_states:
        delta = remove_state(state, delta)

    regex = {'regex': delta[0][1]}
    output = json.dumps(regex, indent=4)
    with open(sys.argv[2], 'w') as f:
        f.write(output)


from rest_framework import serializers

from carts.mixins import TokenMixin
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated

from .models import Order, StoreWiseOrder, PurchaseItem, Purchase
from datetime import timedelta
from products.models import Product, ProductImage
from products.serializers import VariationSerializer
from carts.models import Cart, CartItem
from store.models import Store
from store.serializers import StoreWiseOrderSerializer, StoreSerializer
import pprint
from django.contrib.auth import get_user_model
from django.conf import settings
from hms.utils import jwt_response_payload_handler
User = get_user_model()

# parse order token
# check order not complete
# nonce is coming through
# mark cart complete
# mark order done

# class QuotationSerializer(serializers.ModelSerializer):
# 	# authentication_classes = [, BasicAuthentication]
# 	permission_classes = [IsAuthenticated]
# 	class Meta:
# 		model = Quotation
# 		fields= '__all__'
# 		# fields = []

class FinalizedOrderSerializer(TokenMixin, serializers.Serializer):
	order_token = serializers.CharField()
	payment_method_nonce = serializers.CharField()
	order_id =  serializers.IntegerField(required=False)
	user_checkout_id = serializers.IntegerField(required=False)

	def validate(self, data):
		order_token = data.get("order_token")
		order_data = self.parse_token(order_token)
		order_id = order_data.get("order_id")
		user_checkout_id = order_data.get("user_checkout_id")

		try:
			order_obj = Order.objects.get(id=order_id, user__id=user_checkout_id)
			data["order_id"] = order_id
			data["user_checkout_id"] = user_checkout_id
		except:
			raise serializers.ValidationError("This is not a valid order for this user.")

		payment_method_nonce = data.get("payment_method_nonce")
		if payment_method_nonce == None:
			raise serializers.ValidationError("This is not a valid payment method nonce")

		return data

class OrderDetailSerializer(serializers.ModelSerializer):
	url = serializers.HyperlinkedIdentityField(view_name="order_detail_api")
	subtotal = serializers.SerializerMethodField()
	class Meta:
		model = Order
		fields = [
			"url",
			"order_id",
			"user",
			"shipping_address",
			"billing_address",
			"shipping_total_price",
			"subtotal",
			"order_total",
		]

	def get_subtotal(self, obj):
		return obj.cart.subtotal

class OrderSerializer(serializers.ModelSerializer):
	subtotal = serializers.SerializerMethodField()
	class Meta:
		model = Order
		fields = [
			"id",
			"user",
			"shipping_address",
			"billing_address",
			"shipping_total_price",
			"subtotal",
			"order_total",
		]

	def get_subtotal(self, obj):
		return obj.cart.subtotal

# class UserAddressSerializer(serializers.ModelSerializer):
# 	class Meta:
# 		model = UserAddress
# 		fields = [
# 			"id",
# 			"user",
# 			"type",
# 			"street",
# 			"state",
# 			"city",
# 			"zipcode",
# 			"phone"
# 		]

	# def create(self,  validated_data):
	# 	user = self.context['request'].user
	# 	usercheckout = UserCheckout.objects.filter(user_id=user.id).first()

	# 	if usercheckout is None:

	# 		usercheckout = UserCheckout()
	# 		usercheckout.user_id = user.id
	# 		usercheckout.email = user.email
	# 		usercheckout.braintree_id = '0'
	# 		usercheckout.save()

	# 	useraddress = UserAddress.objects.filter(user_id=usercheckout.id).first()
	# 	if useraddress is None:
	# 		print('sadsd')
	# 		useraddress = UserAddress()

	# 	useraddress.user_id = usercheckout.id
	# 	useraddress.type = validated_data.get('type')
	# 	useraddress.street = validated_data.get('street')
	# 	useraddress.city =  validated_data.get('city')
	# 	useraddress.zipcode = validated_data.get('zipcode')
	# 	useraddress.state = validated_data.get('state')
	# 	useraddress.phone = validated_data.get('phone')
	# 	useraddress.save()
	# 	return useraddress

from . import service as OrderService

# /api/api/create_order/ #CartOrderApiView(CreateAPIView):
class CartOrderSerializer(serializers.ModelSerializer):
	order_total = serializers.DecimalField(required=False, max_digits=50, decimal_places=2,)
	class Meta:
		model = Order
		fields = '__all__'

	def create(self, validated_data):
		#pprint.pprint(self.context['request'].__dict__)
		#pprint.pprint(validated_data)
		user =  self.context['request'].user
		print( type(validated_data))
		#pprint.pprint(validated_data)
		validated_data['user_id'] = user.id

		order = OrderService.CreateOrderFromCart(validated_data)
		return order

	# # def saveStoreWiseOrder(self, order, user):
	# # 	print('order::')
	# # 	print(order)
	# # 	cart = order.cart
	# # 	cart_items = cart.items
	# # 	cart_items = CartItem.objects.filter(cart_id=cart.id)
	# # 	ordered_by = Store.objects.filter(fk_user_id=user.id).first()
	# 	#ordered_by_store = ordered_by.id
	# 	#print(ordered_by_store)

	# 	# print('asdasdasdasd')
	# 	for variation in cart_items:
	# 		print(variation)
	# 		store = variation.item.product.fk_store
	# 		order_id = order.order_id
	# 		store_id = store.id
	# 		store_wise = StoreWiseOrder.objects.filter(order_id=order_id).filter(fk_ordered_store_id=store_id).first()
	# 		pprint.pprint(['storewise=', store_wise])
	# 		if store_wise is None:
	# 			store_wise = StoreWiseOrder()
	# 		store_wise.order_id = order.order_id
	# 		store_wise.order_total = order.order_total
	# 		store_wise.billing_address = order.billing_address
	# 		store_wise.shipping_address = order.shipping_address
	# 		store_wise.user_id = order.user_id
	# 		store_wise.cart_id = order.cart_id
	# 		store_wise.fk_auth_user_id = order.fk_auth_user_id
	# 		store_wise.order_latitude = order.order_latitude
	# 		store_wise.order_longitude = order.order_longitude
	# 		store_wise.fk_ordered_store = store
	# 		store_wise.fk_ordered_by_store = ordered_by
	# 		store_wise.fk_payment_method = order.fk_payment_method
	# 		store_wise.save()
	# 		variation.fk_storewise_order_id = store_wise.id
	# 		variation.save()
	# 	store_wise_orders = StoreWiseOrder.objects.filter(order_id=order_id)
	# 	for store_wise_order in store_wise_orders:
	# 		sw_cart_items =  CartItem.objects.filter(fk_storewise_order_id=store_wise_order.id) #store_wise_order.fk_storewise_order_id
	# 		store_wise_order.order_total = 0
	# 		# is_depo = Store.objects.filter(fk_user_id=user.id).filter(fk_store_type_id=2).first()
	# 		# if not is_depo:
	# 		if store_wise_order.order_latitude and store_wise_order.order_longitude:
	# 			store_wise_order.fk_route = get_nearest_route(
	# 				store_wise_order.order_latitude,
	# 				store_wise_order.order_longitude,
	# 				store_wise_order.fk_ordered_store.id,
	# 				None
	# 			)
	# 		for cart_item in sw_cart_items:
	# 			store_wise_order.order_total+=cart_item.line_item_total

	# 		store_wise_order.save()

			# print(variation.product)

class OrderListStoreSerializer(serializers.ModelSerializer):
	billing_address = serializers.SerializerMethodField()
	mobile = serializers.SerializerMethodField()
	payment_method = serializers.SerializerMethodField()
	class Meta:
		model = Order
		fields = ['id', 'status', 'is_delivered', 'is_paid',
		'order_longitude', 'order_latitude', 'cart', 'user', 'order_total',
		'billing_address', 'fk_ordered_store', 'fk_delivery_user',
		 'fk_payment_method', 'mobile', "payment_method"]

	def get_billing_address(self, obj):
		return str(obj.billing_address.street)

	def get_mobile(self, obj):
		return obj.user.user.mobile

	def get_payment_method(self, obj):
		title=""
		if obj.fk_payment_method:
			title = obj.fk_payment_method.title
		return title

from users.serializers import UserSerializer

class StoreWiseOrderListSerializer(serializers.ModelSerializer):
	# billing_address = serializers.SerializerMethodField()
	ordered_stored_name = serializers.SerializerMethodField()
	total_order_price = serializers.SerializerMethodField()
	customer_name = serializers.SerializerMethodField()
	address = serializers.SerializerMethodField()
	status = serializers.SerializerMethodField()
	created_at = serializers.SerializerMethodField()
	#ordered_time = serializers.SerializerMethodField()
	# fk_auth_user = UserSerializer()

	class Meta:
		model = StoreWiseOrder
		fields = [

			"id",
            "shipping_total_price",
            "order_total",
            "order_id",
            "is_delivered",
            "is_paid",
            "is_transit",
            "is_cancelled",
            "created_at",
           # "ordered_time",
            "updated_at",
            "order_latitude",
            "order_longitude",
            "cart",
            "fk_auth_user",
            "fk_ordered_store",
            "fk_delivery_user",
            "fk_payment_method",
            "fk_ordered_by_store_id",
            "ordered_stored_name",
            "total_order_price",
            "customer_name",
            "address",
            "status"

		]
	def get_created_at(self, obj):
		order_time = ((obj.created_at + timedelta(hours=5, minutes=45))).strftime("%Y-%m-%d, %I:%M %p")
		return order_time

	# def get_ordered_time(self, obj):
	# 	print(obj.created_at)
	# 	order_time = ((obj.created_at + timedelta(hours=5, minutes=45))).strftime("%Y-%m-%d, %I:%M %p")
	# 	return order_time

	def get_status(self, obj):
		status = "pending"
		if obj.is_delivered:
			status = "delivered"
		elif obj.is_transit:
			status = "transit"
		elif obj.is_cancelled:
			status = "cancelled"

		return status

	def get_ordered_stored_name(self, obj):
		abc = ""
		abc = Store.objects.filter(pk=obj.fk_ordered_by_store_id).first()

		if abc:
			return abc.title

		return abc
	def get_address(self, obj):
		cutomer_address = ""
		customer_address = UserAddress.objects.filter(user_id=obj.fk_auth_user_id).first()
		if customer_address:
			return str(customer_address.city + customer_address.street)
		return cutomer_address

	def get_customer_name(self, obj):
		customer_name = ""
		customer = User.objects.filter(pk=obj.fk_auth_user_id).first()
		if customer:
			return str(customer.firstname + ' '+ customer.lastname + ' '+ customer.mobile)
		return customer_name

	def get_total_order_price(self, obj):
		total_price = ""
		total_price = Order.objects.filter(order_id=obj.order_id).first()
		if total_price:
			total_price = total_price.order_total
		return total_price
		# def get_ordered_by(self, obj):
		# 	print(obj)
		# 	ordered_by = ""
		# 	if obj.fk_ordered_by_store_id:
		# 		ordered_by = Store.objects.filter(pk=obj.fk_ordered_by_store_id)
		# 	return ordered_by
	# def get_billing_address(self, obj):
	# 	return str(obj.billing_address.street)

	# def get_mobile(self, obj):
	# 	return obj.user.user.mobile

class UpdateOrderStatusSerializer(serializers.ModelSerializer):
	class Meta:
		model = Order
		fields = '__all__'

class UpdateStoreWiseOrderStatusSerializer(serializers.ModelSerializer):
	class Meta:
		model = StoreWiseOrder
		fields = '__all__'

class CartOrderListStoreSerializer(serializers.ModelSerializer):
	# cart_orders = serializers.SerializerMethodField()
	class Meta:
		model = CartItem
		fields = '__all__'

class CartItemSerializer(serializers.ModelSerializer):
	#item = CartVariationSerializer(read_only=True)
	# url = serializers.HyperlinkedIdentityField(view_name='products_detail_api')
	item = serializers.SerializerMethodField()
	product_id = serializers.SerializerMethodField()
	item_title = serializers.SerializerMethodField()
	product = serializers.SerializerMethodField()
	price = serializers.SerializerMethodField()
	image = serializers.SerializerMethodField()
	class Meta:
		model = CartItem
		fields = [
			# "url",
			"product_id",
			"image",
			"item",
			"item_title",
			"price",
			"product",
			"quantity",
			"line_item_total",
		]

	def get_item(self,obj):
		return obj.item.id

	def get_product_id(self, obj):
		return obj.id

	def get_item_title(self, obj):
		return "%s %s" %(obj.item.product.title, obj.item.title)

	def get_product(self, obj):
		return obj.item.product.id

	def get_price(self, obj):
		print(obj.item.sale_price)
		print(obj.item.price)
		print(obj.item.id)
		# print(obj.item.sale_price)
		if obj.item.sale_price is None:
			return obj.item.price
		return obj.item.sale_price

	def get_image(self, obj):
		# image_url = ProductImage.objects.filter(product_id=obj.item.id).first()
		variation = obj.item
		product = variation.product

		image_url = ProductImage.objects.filter(product=product).first()
		# print(obj.item.id)
		# print(obj.__dict__)
		# print(image_url)
		# return ""
		# print(list(image_url.values('image')))

		imageUrl = "/static/no-image.jpg"
		if image_url:
			d = image_url.__dict__
			if 'image' in d:
				imageUrl = d['image']

		# return image_url.image

		return imageUrl

		# cart_items = CartItem.objects.filter(cart_id=cart.id)

class PurchaseItemSerializer(serializers.ModelSerializer):
	fk_variation = VariationSerializer()
	class Meta:
		model = PurchaseItem
		fields = '__all__'