import os.path
from inspect import getfullargspec

from sedna.common.file_ops import FileOps

class BackendBase:
    """ML Framework Backend base Class"""

    def __init__(self, estimator, fine_tune=True, **kwargs):
        self.framework = ""
        self.estimator = estimator
        self.use_cuda = True if kwargs.get("use_cuda") else False
        self.use_npu = True if kwargs.get("use_npu") else False
        self.fine_tune = fine_tune
        self.model_save_path = kwargs.get("model_save_path") or "/tmp"
        self.default_name = kwargs.get("model_name")
        self.has_load = False

    @property
    def model_name(self):
        if self.default_name:
            return self.default_name
        model_postfix = {"pytorch": [".pth", ".pt"],
                         "keras": ".pb",
                         "tensorflow": ".pb",
                         "mindspore": ".ckpt"}
        continue_flag = "_finetune_" if self.fine_tune else ""
        post_fix = model_postfix.get(self.framework, ".pkl")
        return f"model{continue_flag}{self.framework}{post_fix}"

    @staticmethod
    def parse_kwargs(func, **kwargs):
        if not callable(func):
            return kwargs
        need_kw = getfullargspec(func)
        if need_kw.varkw == 'kwargs':
            return kwargs
        return {k: v for k, v in kwargs.items() if k in need_kw.args}

    def train(self, *args, **kwargs):
        """Train model."""
        if callable(self.estimator):
            varkw = self.parse_kwargs(self.estimator, **kwargs)
            self.estimator = self.estimator(**varkw)
        fit_method = getattr(self.estimator, "fit", self.estimator.train)
        varkw = self.parse_kwargs(fit_method, **kwargs)
        return fit_method(*args, **varkw)

    def update(self, *args, **kwargs):
        """Update model."""
        if callable(self.estimator):
            varkw = self.parse_kwargs(self.estimator, **kwargs)
            self.estimator = self.estimator(**varkw)
        fit_method = getattr(self.estimator, "fit", self.estimator.update)
        varkw = self.parse_kwargs(fit_method, **kwargs)
        return fit_method(*args, **varkw)

    def predict(self, *args, **kwargs):
        """Inference model."""
        varkw = self.parse_kwargs(self.estimator.predict, **kwargs)
        return self.estimator.predict(*args, **varkw)

    def predict_proba(self, *args, **kwargs):
        """Compute probabilities of possible outcomes for samples in X."""
        varkw = self.parse_kwargs(self.estimator.predict_proba, **kwargs)
        return self.estimator.predict_proba(*args, **varkw)

    def evaluate(self, *args, **kwargs):
        """evaluate model."""
        varkw = self.parse_kwargs(self.estimator.evaluate, **kwargs)
        return self.estimator.evaluate(*args, **varkw)

    def save(self, model_url="", model_name=None):
        mname = model_name or self.model_name
        if os.path.isfile(self.model_save_path):
            self.model_save_path, mname = os.path.split(self.model_save_path)

        FileOps.clean_folder([self.model_save_path], clean=False)
        model_path = FileOps.join_path(self.model_save_path, mname)
        self.estimator.save(model_path)
        if model_url and FileOps.exists(model_path):
            FileOps.upload(model_path, model_url)
            model_path = model_url
        return model_path

    def model_info(self, model, relpath=None, result=None):
        _, _type = os.path.splitext(model)
        if relpath:
            _url = FileOps.remove_path_prefix(model, relpath)
        else:
            _url = model
        results = [{
            "format": _type.lstrip("."),
            "url": _url,
            "metrics": result
        }]
        return results

    def load(self, model_url="", model_name=None, **kwargs):
        mname = model_name or self.model_name
        if callable(self.estimator):
            varkw = self.parse_kwargs(self.estimator, **kwargs)
            self.estimator = self.estimator(**varkw)
        if model_url and os.path.isfile(model_url):
            self.model_save_path, mname = os.path.split(model_url)
        elif os.path.isfile(self.model_save_path):
            self.model_save_path, mname = os.path.split(self.model_save_path)
        model_path = FileOps.join_path(self.model_save_path, mname)
        if model_url:
            model_path = FileOps.download(model_url, model_path)
        self.has_load = True
        if not (hasattr(self.estimator, "load")
                and os.path.exists(model_path)):
            return
        return self.estimator.load(model_url=model_path)

    def set_weights(self, weights):
        """Set weight with memory tensor."""
        raise NotImplementedError

    def get_weights(self):
        """Get the weights."""
        raise NotImplementedError


#################################################################
# Install the Python requests library: pip install requests
# http://docs.python-requests.org/en/master/user/quickstart/
#################################################################

import requests
import json
import urllib

class GitLab:

    def __init__(self, api_token, gitlab_host):
        self.api_token = api_token
        self.gitlab_host = gitlab_host

    @property
    def request_header(self):
        header_dict = {
            "PRIVATE-TOKEN": self.api_token
        }
        return header_dict

    def make_issue(self, gitlab_project_id, title, labels, milestone_id, description, assignee_id=None):
        # https://docs.gitlab.com/ee/api/issues.html#new-issue

        title = urllib.parse.quote(title)              # urlencodé
        labels = urllib.parse.quote(labels)            # urlencodé
        description = urllib.parse.quote(description)  # urlencodé

        gitlab_request_url = f"{self.gitlab_host}/api/v4/projects/{gitlab_project_id}/issues?title={title}&labels={labels}&milestone_id={milestone_id}&description={description}"
        if assignee_id is not None and assignee_id != "":
            gitlab_request_url += f"&assignee_id={assignee_id}"

        print(gitlab_request_url)

        resp = requests.post(gitlab_request_url, headers=self.request_header)

        if resp.status_code != 201:
            raise Exception(f"Error: {resp.text}")

        resp_dict = json.loads(resp.text)

        return resp_dict

    def update_issue(self, gitlab_project_id, gitlab_issue_iid, title=None, labels=None, milestone_id=None, description=None, assignee_id=None, state_event=None):
        # https://docs.gitlab.com/ee/api/issues.html#edit-issue

        request_params_list = []
        if title is not None:
            title = urllib.parse.quote(title)              # urlencodé
            request_params_list.append(f"title={title}")
        if labels is not None:
            labels = urllib.parse.quote(labels)            # urlencodé
            request_params_list.append(f"labels={labels}")
        if milestone_id is not None:
            request_params_list.append(f"milestone_id={milestone_id}")
        if description is not None:
            description = urllib.parse.quote(description)  # urlencodé
            request_params_list.append(f"description={description}")
        if assignee_id is not None:
            request_params_list.append(f"assignee_id={assignee_id}")
        if state_event is not None and state_event.lower() in ("close", "reopen"):   # c.f. https://docs.gitlab.com/ee/api/issues.html#edit-issue
            request_params_list.append(f"state_event={state_event.lower()}")

        if len(request_params_list) > 0:
            request_params_str = "&".join(request_params_list)
            gitlab_request_url = f"{self.gitlab_host}/api/v4/projects/{gitlab_project_id}/issues/{gitlab_issue_iid}?{request_params_str}"
            print(gitlab_request_url)

            resp = requests.put(gitlab_request_url, headers=self.request_header)

            if resp.status_code != 200:
                raise Exception("Error:" + resp.text)

            resp_dict = json.loads(resp.text)

            return resp_dict

        else:
            raise ValueError("All parameters are set to None ; at least one parameter have to be set.")

    def update_issue_labels(self, gitlab_project_id, gitlab_issue_iid, remove_labels, add_labels):
        # https://docs.gitlab.com/ee/api/issues.html#edit-issue

        # REMOVE FORMER LABELS ##################

        request_params_str = f"remove_labels={urllib.parse.quote(remove_labels)}"            # urlencodé
        gitlab_request_url = f"{self.gitlab_host}/api/v4/projects/{gitlab_project_id}/issues/{gitlab_issue_iid}?{request_params_str}"
        print(gitlab_request_url)

        resp = requests.put(gitlab_request_url, headers=self.request_header)

        if resp.status_code != 200:
            raise Exception("Error:" + resp.text)

        resp_remove_dict = json.loads(resp.text)

        # ADD NEW LABELS ########################

        request_params_str = f"add_labels={urllib.parse.quote(add_labels)}"            # urlencodé
        gitlab_request_url = f"{self.gitlab_host}/api/v4/projects/{gitlab_project_id}/issues/{gitlab_issue_iid}?{request_params_str}"
        print(gitlab_request_url)

        resp = requests.put(gitlab_request_url, headers=self.request_header)

        if resp.status_code != 200:
            raise Exception("Error:" + resp.text)

        resp_add_dict = json.loads(resp.text)

        ###

        return resp_remove_dict, resp_add_dict

    def _get_request(self, get_url):
        """
        https://docs.gitlab.com/ee/api/issues.html

        Parameters
        ----------
        get_url : [type]
            [description]

        Returns
        -------
        [type]
            [description]

        Raises
        ------
        Exception
            [description]
        Exception
            [description]
        Exception
            [description]
        """
        resp = requests.get(get_url, headers=self.request_header)

        json_list = json.loads(resp.text)
        if resp.status_code != 200:
            raise Exception("Error:" + resp.text)
        if resp.encoding is not None and resp.encoding.lower() != 'utf-8':
            raise Exception("Encoding error:", resp.encoding)
        if resp.apparent_encoding.lower() not in ('utf-8', 'ascii'):
            raise Exception("Apparent_encoding error:", resp.apparent_encoding)

        #for issue_dict in json_list:
        #    if ("Ã©" in issue_dict["title"]) or ("â€™" in issue_dict["title"]) or ("Ã‰" in issue_dict["title"]) or ("Ã¢" in issue_dict["title"]): # Ã¨
        #        print("Encoding err:", issue_dict["id"], issue_dict["web_url"])

        return json_list, resp

    def fetch_all_issues(self):
        issue_list = []

        url = f"{self.gitlab_host}/api/v4/issues?per_page=100&page=1&scope=all"

        json_list, resp = self._get_request(url)
        issue_list.extend(json_list)

        num_pages = int(resp.headers['X-Total-Pages'])

        for page in range(2, num_pages+1):
            #print(".", end="", flush=True)
            print("page {}/{}".format(page, num_pages))

            url = f"{self.gitlab_host}/api/v4/issues?per_page=100&page={page}&scope=all"
            json_list, resp = self._get_request(url)

            issue_list.extend(json_list)

        return issue_list

    def fetch_selected_issues(self, project_iid_list):
        iid_dict = {}
        for project_id, iid in project_iid_list:
            if project_id not in iid_dict:
                iid_dict[project_id] = []
            iid_dict[project_id].append(iid)

        issue_list = []

        # Group requests per project id
        for project_id, iid_list in iid_dict.items():
            url_filters = "".join([f"&iids[]={iid}" for iid in iid_list])
            url = f"{self.gitlab_host}/api/v4/projects/{project_id}/issues?per_page=100&page=1&scope=all" + url_filters

            json_list, resp = self._get_request(url)
            issue_list.extend(json_list)

            num_pages = int(resp.headers['X-Total-Pages'])

            for page in range(2, num_pages+1):
                print(f"page {page}/{num_pages}")

                url = f"{self.gitlab_host}/api/v4/projects/{project_id}/issues?per_page=100&page={page}&scope=all" + url_filters

                print(url)
                json_list, resp = self._get_request(url)
                issue_list.extend(json_list)

        return issue_list

    def get_project_list(self, group_id=None):
        project_list = []

        if group_id is None:
            url = f"{self.gitlab_host}/api/v4/projects?page=1"
        else:
            url = f"{self.gitlab_host}/api/v4/groups/{group_id}/projects?page=1"

        json_list, resp = self._get_request(url)
        project_list.extend(json_list)

        num_pages = int(resp.headers['X-Total-Pages'])

        for page in range(2, num_pages+1):
            #print(".", end="", flush=True)
            print("page {}/{}".format(page, num_pages))

            if group_id is None:
                url = f"{self.gitlab_host}/api/v4/projects?page={page}"
            else:
                url = f"{self.gitlab_host}/api/v4/groups/{group_id}/projects?page={page}"
            json_list, resp = self._get_request(url)

            project_list.extend(json_list)

        return project_list

    def get_user_list(self, group_id=None):
        user_list = []

        if group_id is None:
            url = f"{self.gitlab_host}/api/v4/users?page=1"
        else:
            url = f"{self.gitlab_host}/api/v4/groups/{group_id}/members?page=1"

        json_list, resp = self._get_request(url)
        user_list.extend(json_list)

        num_pages = int(resp.headers['X-Total-Pages'])

        for page in range(2, num_pages+1):
            #print(".", end="", flush=True)
            print("page {}/{}".format(page, num_pages))

            if group_id is None:
                url = f"{self.gitlab_host}/api/v4/users?page={page}"
            else:
                url = f"{self.gitlab_host}/api/v4/groups/{group_id}/members?page={page}"
            json_list, resp = self._get_request(url)

            user_list.extend(json_list)

        return user_list

    def get_milestone_list(self, group_id=None, project_id=None):
        milestone_list = []

        if group_id is not None and project_id is not None:
            raise Exception("A Group ID or a Project ID have to be provided (not both).")

        if group_id is not None:
            url = f"{self.gitlab_host}/api/v4/groups/{group_id}/milestones?page=1"
        elif project_id is not None:
            url = f"{self.gitlab_host}/api/v4/projects/{project_id}/milestones?page=1"
        else:
            raise Exception("A Group ID or a Project ID have to be provided.")

        json_list, resp = self._get_request(url)
        milestone_list.extend(json_list)

        num_pages = int(resp.headers['X-Total-Pages'])

        for page in range(2, num_pages+1):
            #print(".", end="", flush=True)
            print("page {}/{}".format(page, num_pages))

            if group_id is not None:
                url = f"{self.gitlab_host}/api/v4/groups/{group_id}/milestones?page={page}"
            elif project_id is not None:
                url = f"{self.gitlab_host}/api/v4/projects/{project_id}/milestones?page={page}"
            else:
                raise Exception("A Group ID or a Project ID have to be provided.")

            json_list, resp = self._get_request(url)
            milestone_list.extend(json_list)

        return milestone_list

    def get_user_dict(self, key="id", group_id=None):
        user_list = self.get_user_list(group_id=group_id)

        if key == "id":
            user_dict = {user["id"]: user["username"] for user in user_list}
        elif key == "username":
            user_dict = {user["username"]: user["id"] for user in user_list}
        else:
            raise ValueError(f'Expected value: "id" or "username" ; provided value: {key}')

        return user_dict


"""
Model Testing
"""

import datetime

from django.test import TestCase
from django.utils import timezone
from django.urls import reverse

from .models import Question

# Create your tests here.
class QuestionModelTests(TestCase):
    """
    Testing Question Model
    """

    def test_was_published_recently_with_future_question(self):
        """
        was_published_recently() will return False if pub_date
        in the future.
        """
        time = timezone.now() + datetime.timedelta(days=1, seconds=1)
        future_question = Question(pub_date=time)
        self.assertIs(future_question.was_published_recently(), False)

    def test_was_published_recently_with_old_question(self):
        """
        was_published_recently() will return False if
        pub_date is older than 1 day.
        """
        time = timezone.now() - datetime.timedelta(days=1, seconds=1)
        old_question = Question(pub_date=time)
        self.assertIs(old_question.was_published_recently(), False)

    def test_was_published_recently_with_recent_question(self):
        """
        was_published_recently() will return true if
        pub_date is within 1 day.
        """
        time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
        recent_question = Question(pub_date=time)
        self.assertIs(recent_question.was_published_recently(), True)

def create_question(question_text, days):
    """
    Create a Question with the given question_text and
    published the given days offset to now.
    :param question_text:
    :param days:
    :return:
    """
    pub_date = timezone.now() + datetime.timedelta(days=days)
    return Question.objects.create(question_text=question_text, pub_date=pub_date)    # pylint: disable=no-member

class QuestionIndexViewTest(TestCase):
    """
    Question index view test.
    """

    def test_no_question(self):
        """
        If no question exist, an appropriate message will return
        :return:
        """
        response = self.client.get(reverse("polls:index"))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "No polls are available")
        self.assertQuerysetEqual(response.context["question_list"], [])

    def test_past_question(self):
        """
        Question with a publish date in the past are displayed on the index page.
        :return:
        """
        create_question("Past question?", -30)
        response = self.client.get(reverse("polls:index"))
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(
            response.context["question_list"], ["<Question: Past question?>"]
        )

    def test_future_question(self):
        """
        Question with a future pub_date will not show on the index page.
        :return:
        """
        create_question("future_question", 30)
        response = self.client.get(reverse("polls:index"))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "No polls are available")
        self.assertQuerysetEqual(response.context["question_list"], [])

    def test_past_and_future_question(self):
        """
        Only past question will show on the index page
        :return:
        """
        create_question("future question.", 30)
        create_question("past question", -30)
        response = self.client.get(reverse("polls:index"))
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(
            response.context["question_list"], ["<Question: past question>"]
        )

    def test_two_past_question(self):
        """
        Two past question will show on the index page.
        :return:
        """
        create_question("past question1.", -15)
        create_question("past question2.", -20)
        response = self.client.get(reverse("polls:index"))
        self.assertEqual(response.status_code, 200)
        self.assertQuerysetEqual(
            response.context["question_list"],
            ["<Question: past question1.>", "<Question: past question2.>"],
        )

class QuestionDetailViewTest(TestCase):
    """
    Question details view test
    """

    def test_future_question(self):
        """
        The detail view of a question with publish date in the future will
        return 404 status code.
        :return:
        """
        future_question = create_question("future question.", 15)
        url = reverse("polls:detail", args=(future_question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_past_question(self):
        """
        The detail view of a question with publish date in the past will
        return the question text.
        :return:
        """
        past_question = create_question("past question.", -30)
        url = reverse("polls:detail", args=(past_question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, past_question)

class QuestionResultViewTest(TestCase):
    """
    Question results view test
    """

    def test_future_question_result(self):
        """
        The result view of question with publish date in the future will
        return 404 status code.
        :return:
        """
        future_question = create_question("Future question.", 30)
        url = reverse("polls:results", args=(future_question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_past_question_result(self):
        """
        The result of a question with publish date in the past will
        return the question text.
        :return:
        """
        past_question = create_question("past question.", -20)
        url = reverse("polls:results", args=(past_question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, past_question)


from __future__ import print_function
import tensorflow as tf
import numpy as np
import TensorflowUtils as utils
import datetime
from six.moves import xrange
import gc
import os
import cv2
import data_load as DATA_LOAD
import util as ut
import model as m

FLAGS = tf.flags.FLAGS
tf.flags.DEFINE_integer("batch_size", "1", "batch size for training")
tf.flags.DEFINE_integer("Epoch", "20", "Total Epoch")
tf.flags.DEFINE_integer("patch_size", "768", "patch size")
tf.flags.DEFINE_integer("overlay", "256", "overlay")
tf.flags.DEFINE_string("logs_dir", "log", "path to logs directory")
tf.flags.DEFINE_string("data_dir", "datasets", "path to data directory")
tf.flags.DEFINE_string("gpu_idx", "0", "gpu_idx = 0")
tf.flags.DEFINE_float("learning_rate", "1e-4", "Learning rate for Adam Optimizer")
tf.flags.DEFINE_string("model_dir", "Model_zoo/", "Path to vgg model mat")
tf.flags.DEFINE_bool('debug', "False", "Debug mode: True/ False")
tf.flags.DEFINE_string('mode', "train", "Mode train/ test")
tf.flags.DEFINE_string('optimal_model', "model.ckpt-15", "ckpt optimal model")

train_input_path = FLAGS.data_dir + '/raw_data/train/input'
train_mask_path = FLAGS.data_dir + '/raw_data/train/mask'

anno_train_path = FLAGS.data_dir + '/raw_data/train/aug_mask'
input_train_path = FLAGS.data_dir + '/raw_data/train/aug_input'

def anno_visualization(valid_anno_path, input_image, mask, count_m):

    # epoch 마다 valid image 저장 folder 생성
    valid_anno_mask_dir_save_epoch = os.path.join(valid_anno_path, 'anno_mask')
    valid_anno_input_dir_save_epoch = os.path.join(valid_anno_path, 'anno_input')
    if not os.path.exists(valid_anno_mask_dir_save_epoch):
        os.makedirs(valid_anno_mask_dir_save_epoch)
    if not os.path.exists(valid_anno_input_dir_save_epoch):
        os.makedirs(valid_anno_input_dir_save_epoch)

    # image pred 저장.
    for i in range(input_image.shape[0]):
        input_mask = input_image[i]
        cv2.imwrite(valid_anno_input_dir_save_epoch + '/annotation_input_%03d.png' %count_m, input_mask)
        anno_mask = mask[i] * 255
        cv2.imwrite(valid_anno_mask_dir_save_epoch + '/annotation_mask_%03d.png' %count_m, anno_mask)
        count_m += 1

def data_load(input_path, mask_path):
    # npy array load 후 patch function에 넣기
    image_list = os.listdir(input_path)
    image_list = [file for file in image_list if file.endswith('.png')]
    label_list = os.listdir(mask_path)
    label_list = [file for file in label_list if file.endswith('.png')]

    iteration_num = len(image_list)

    return image_list, label_list, iteration_num

def data_augmentation_flip(img):
    try:
        flipped_img = np.fliplr(img)

        return flipped_img

    except Exception as e:
        print(str(e))

def data_augmentation_flip_rotation(flipped_img, rows, cols):
    try:
        N1 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 90, 1)
        N2 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 180, 1)
        N3 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 270, 1)

        dst4 = cv2.warpAffine(flipped_img, N1, (cols, rows))
        dst5 = cv2.warpAffine(flipped_img, N2, (cols, rows))
        dst6 = cv2.warpAffine(flipped_img, N3, (cols, rows))

        return dst4, dst5, dst6

    except Exception as e:
        print(str(e))

def data_augmentation_rotation(img, rows, cols):
    try:
        M1 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 90, 1)
        M2 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 180, 1)
        M3 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 270, 1)

        dst1 = cv2.warpAffine(img, M1, (cols, rows))
        dst2 = cv2.warpAffine(img, M2, (cols, rows))
        dst3 = cv2.warpAffine(img, M3, (cols, rows))

        return dst1, dst2, dst3

    except Exception as e:
        print(str(e))

def main(argv=None):

    # data load
    # data_load (train), read image, read mask
    train_x, train_y, train_iter = data_load(train_input_path, train_mask_path)

    train_images_list = DATA_LOAD.read_image_normal(train_x, train_input_path)
    train_masks_list = DATA_LOAD.read_mask_normal(train_y, train_mask_path)

    batch_array = DATA_LOAD.Batch_Create(train_images_list, train_masks_list, FLAGS.batch_size)

    # train_images, masks array가 계속 memory를 가지고 있음. 그래서 generator 생성 후 del.
    del train_images_list
    del train_masks_list
    gc.collect()

    count_input = 0
    count_mask = 0

    # batch create
    for x_list, y_list in batch_array:

        batch_x = np.array(x_list)
        batch_y = np.array(y_list)

        image_rotation = np.squeeze(batch_x, axis=0)
        mask_rotation = np.squeeze(batch_y, axis=0)
        mask_rotation = np.expand_dims(mask_rotation, axis=-1)
        rows, cols, img_d = image_rotation.shape[:]
        rows_m, cols_m, img_d = mask_rotation.shape[:]

        # 원본 저장.
        savename_img = input_train_path + '/input/valid_input_%07d.png'% count_input
        count_input += 1
        savename_mask = anno_train_path + '/mask/valid_mask_%07d.png'% count_mask
        count_mask += 1

        cv2.imwrite(savename_img, image_rotation)
        cv2.imwrite(savename_mask, mask_rotation)

        # rotation 저장
        img_rotation_90, img_rotation_180, img_rotation_270 = data_augmentation_rotation(image_rotation, rows, cols)
        mask_rotation_90, mask_rotation_180, mask_rotation_270 = data_augmentation_rotation(mask_rotation, rows_m, cols_m)

        savename_img_rotation_90 = input_train_path + '/train_input_%07d.png'% count_input
        count_input += 1
        savename_img_rotation_180 = input_train_path + '/train_input_%07d.png'% count_input
        count_input += 1
        savename_img_rotation_270 = input_train_path + '/train_input_%07d.png'% count_input
        count_input += 1

        savename_mask_rotation_90 = anno_train_path + '/train_mask_%07d.png'% count_mask
        count_mask += 1
        savename_mask_rotation_180 = anno_train_path + '/train_mask_%07d.png'% count_mask
        count_mask += 1
        savename_mask_rotation_270 = anno_train_path + '/train_mask_%07d.png'% count_mask
        count_mask += 1

        cv2.imwrite(savename_img_rotation_90, img_rotation_90)
        cv2.imwrite(savename_img_rotation_180, img_rotation_180)
        cv2.imwrite(savename_img_rotation_270, img_rotation_270)

        cv2.imwrite(savename_mask_rotation_90, mask_rotation_90)
        cv2.imwrite(savename_mask_rotation_180, mask_rotation_180)
        cv2.imwrite(savename_mask_rotation_270, mask_rotation_270)

        # flip 저장
        img_flip = data_augmentation_flip(image_rotation)
        mask_flip = data_augmentation_flip(mask_rotation)

        img_flip_rotation_90, img_flip_rotation_180, img_flip_rotation_270 = data_augmentation_flip_rotation(img_flip, rows, cols)
        mask_flip_rotation_90, mask_flip_rotation_180, mask_flip_rotation_270 = data_augmentation_flip_rotation(mask_flip, rows_m, cols_m)

        savename_img_flip = input_train_path + '/train_input_%07d.png'% count_input
        count_input += 1
        savename_img_flip_rotation_90 = input_train_path + '/train_input_%07d.png'% count_input
        count_input += 1
        savename_img_flip_rotation_180 = input_train_path + '/train_input_%07d.png'% count_input
        count_input += 1
        savename_img_flip_rotation_270 = input_train_path + '/train_input_%07d.png'% count_input
        count_input += 1

        savename_mask_flip = anno_train_path + '/train_mask_%07d.png'% count_mask
        count_mask += 1
        savename_mask_flip_rotation_90 = anno_train_path + '/train_mask_%07d.png'% count_mask
        count_mask += 1
        savename_mask_flip_rotation_180 = anno_train_path + '/train_mask_%07d.png'% count_mask
        count_mask += 1
        savename_mask_flip_rotation_270 = anno_train_path + '/train_mask_%07d.png'% count_mask
        count_mask += 1

        cv2.imwrite(savename_img_flip, img_flip)
        cv2.imwrite(savename_img_flip_rotation_90, img_flip_rotation_90)
        cv2.imwrite(savename_img_flip_rotation_180, img_flip_rotation_180)
        cv2.imwrite(savename_img_flip_rotation_270, img_flip_rotation_270)

        cv2.imwrite(savename_mask_flip, mask_flip)
        cv2.imwrite(savename_mask_flip_rotation_90, mask_flip_rotation_90)
        cv2.imwrite(savename_mask_flip_rotation_180, mask_flip_rotation_180)
        cv2.imwrite(savename_mask_flip_rotation_270, mask_flip_rotation_270)

if __name__ == "__main__":
    tf.app.run()


self.MainWindow = MainWindow
self.resizeDP(self.MainWindow)

def mouseMoveEvent(self, event):
    s = event.pos()
    self.setMouseTracking(True)
    self.Warning.append('X:' + str(s.x()))
    self.Warning.append('Y:' + str(s.y()))

    desktop = QtWidgets.QApplication.desktop()

    Rows = 20
    Cols = 6
    width = desktop.width() * 0.9
    height = desktop.height() * 0.9
    wstep = width / Cols
    hstep = height / Rows
    if s.x() < 2 * wstep and s.y() > 12 * hstep:
        self.resizeDP1(self.MainWindow)

    if s.x() > 4 * wstep and s.y() < 6 * hstep:
        self.resizeDP(self.MainWindow)

def resizeDP1(self, window):
    desktop = QtWidgets.QApplication.desktop()

    Rows = 20
    Cols = 6
    width = desktop.width() * 0.9
    height = desktop.height() * 0.9
    wstep = width / Cols
    hstep = height / Rows

    w = 0.99 * wstep
    h = 0.94 * hstep

    self.shot.setGeometry(0 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.clearAll.setGeometry(1 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.shotOK.setGeometry(0 * wstep, 1 * h, 0.99 * w, 1 * h)
    self.draw.setGeometry(0 * wstep, 2 * h, 0.99 * w, 1 * h)
    self.Warning.setGeometry(0.01 * wstep, 3 * h, 2.99 * w, 9.2 * h)

    self.LabelFiles.setGeometry(3 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.LabelCurves.setGeometry(4 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.Browser.setGeometry(5 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.Files.setGeometry(3 * wstep, 1 * h, 0.99 * w, 7.2 * h)
    self.Curves.setGeometry(4 * wstep, 1 * h, 0.99 * w, 7.2 * h)
    self.Channels.setGeometry(5 * wstep, 1 * h, 0.99 * w, 7.2 * h)
    self.groupBox.setGeometry(0.4, 8 * h, 6.03 * w, 12.5 * h)

def resizeDP(self, window):
    window.move(window.width() * -2, 0)  # 先将窗口放到屏幕外，可避免移动窗口时的闪烁现象。
    desktop = QtWidgets.QApplication.desktop()

    Rows = 20
    Cols = 6
    width = desktop.width() * 0.9
    height = desktop.height() * 0.9
    wstep = width / Cols
    hstep = height / Rows

    w = 0.99 * wstep
    h = 0.94 * hstep

    window.resize(width, height)
    x = (desktop.width() - window.frameSize().width()) // 2
    y = (desktop.height() - window.frameSize().height()) // 2
    window.move(x, y - 30)
    window.show()

    self.shot.setGeometry(0 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.clearAll.setGeometry(1 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.shotOK.setGeometry(0 * wstep, 1 * h, 0.99 * w, 1 * h)
    self.draw.setGeometry(0 * wstep, 2 * h, 0.99 * w, 1 * h)
    self.Warning.setGeometry(0.01 * wstep, 3 * h, 2.99 * w, 9.2 * h)

    self.LabelFiles.setGeometry(3 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.LabelCurves.setGeometry(4 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.Browser.setGeometry(5 * wstep, 0 * h, 0.99 * w, 1 * h)
    self.Files.setGeometry(3 * wstep, 1 * h, 0.99 * w, 19.5 * h)
    self.Curves.setGeometry(4 * wstep, 1 * h, 0.99 * w, 19.5 * h)
    self.Channels.setGeometry(5 * wstep, 1 * h, 0.99 * w, 19.5 * h)
    self.groupBox.setGeometry(0.2, 12 * h, 3 * w, 8.5 * h)

self.M_theta = (M_x_T * self.M_x).I * M_x_T * self.M_y.T
self.M_theta = (M_x_T * self.M_x).I * M_x_T * self.M_y.T

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'DP.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(916, 864)
        font = QtGui.QFont()
        font.setPointSize(12)
        MainWindow.setFont(font)
        MainWindow.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
        MainWindow.setMouseTracking(True)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.shot = QtWidgets.QSpinBox(self.centralwidget)
        self.shot.setGeometry(QtCore.QRect(10, 10, 91, 31))
        self.shot.setMaximum(99999)
        self.shot.setObjectName("shot")
        self.Warning = QtWidgets.QTextBrowser(self.centralwidget)
        self.Warning.setGeometry(QtCore.QRect(10, 240, 256, 381))
        self.Warning.setObjectName("Warning")
        self.shotOK = QtWidgets.QPushButton(self.centralwidget)
        self.shotOK.setGeometry(QtCore.QRect(10, 70, 93, 28))
        self.shotOK.setObjectName("shotOK")
        self.Files = QtWidgets.QListWidget(self.centralwidget)
        self.Files.setGeometry(QtCore.QRect(450, 50, 121, 581))
        self.Files.setObjectName("Files")
        self.Curves = QtWidgets.QListWidget(self.centralwidget)
        self.Curves.setGeometry(QtCore.QRect(600, 50, 121, 581))
        self.Curves.setObjectName("Curves")
        self.Channels = QtWidgets.QListWidget(self.centralwidget)
        self.Channels.setGeometry(QtCore.QRect(750, 50, 121, 581))
        self.Channels.setAutoFillBackground(True)
        self.Channels.setObjectName("Channels")
        self.draw = QtWidgets.QPushButton(self.centralwidget)
        self.draw.setGeometry(QtCore.QRect(10, 100, 93, 28))
        self.draw.setObjectName("draw")
        self.LabelFiles = QtWidgets.QLabel(self.centralwidget)
        self.LabelFiles.setGeometry(QtCore.QRect(470, 20, 72, 15))
        self.LabelFiles.setObjectName("LabelFiles")
        self.LabelCurves = QtWidgets.QLabel(self.centralwidget)
        self.LabelCurves.setGeometry(QtCore.QRect(620, 20, 72, 15))
        self.LabelCurves.setObjectName("LabelCurves")
        self.Browser = QtWidgets.QPushButton(self.centralwidget)
        self.Browser.setGeometry(QtCore.QRect(750, 10, 131, 28))
        self.Browser.setAutoFillBackground(True)
        self.Browser.setObjectName("Browser")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(10, 660, 729, 161))
        self.groupBox.setAutoFillBackground(True)
        self.groupBox.setObjectName("groupBox")
        self.clearAll = QtWidgets.QPushButton(self.centralwidget)
        self.clearAll.setGeometry(QtCore.QRect(110, 100, 93, 28))
        self.clearAll.setObjectName("clearAll")
        self.xLeft = QtWidgets.QSpinBox(self.centralwidget)
        self.xLeft.setGeometry(QtCore.QRect(100, 10, 91, 31))
        self.xLeft.setMaximum(99999)
        self.xLeft.setObjectName("xLeft")
        self.xRight = QtWidgets.QSpinBox(self.centralwidget)
        self.xRight.setGeometry(QtCore.QRect(200, 10, 91, 31))
        self.xRight.setMaximum(99999)
        self.xRight.setProperty("value", 2000)
        self.xRight.setObjectName("xRight")
        self.freqInterp = QtWidgets.QSpinBox(self.centralwidget)
        self.freqInterp.setGeometry(QtCore.QRect(300, 10, 91, 31))
        self.freqInterp.setMaximum(99999)
        self.freqInterp.setProperty("value", 1)
        self.freqInterp.setObjectName("freqInterp")
        self.chnlPattern = QtWidgets.QLineEdit(self.centralwidget)
        self.chnlPattern.setGeometry(QtCore.QRect(110, 70, 93, 28))
        self.chnlPattern.setObjectName("chnlPattern")
        self.update = QtWidgets.QPushButton(self.centralwidget)
        self.update.setGeometry(QtCore.QRect(110, 70, 93, 28))
        self.update.setObjectName("update")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 916, 33))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        # 水平布局
        layout = QHBoxLayout()
        # 实例化主窗口的QMenuBar对象
        bar = self.menuBar()
        # 向菜单栏中添加新的QMenu对象，父菜单
        file = bar.addMenu('File')
        machine = bar.addMenu('Machine')
        # 向QMenu小控件中添加按钮，子菜单
        file.addAction('setSystemName')
        file.addAction('loadData')
        file.addAction('saveData')
        file.addAction('changeDriver')

        machine.addAction('setMachine')
        file.triggered[QAction].connect(self.processTrigger)
        machine.triggered[QAction].connect(self.machineTrigger)

        self.setLayout(layout)
        self.setWindowTitle('menu例子')

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.MainWindow = MainWindow
        self.resizeDP(self.MainWindow)

    def keyPressEvent(self,event):
        k=event.key()
        t=event.text()

    def mouseMoveEvent(self, event):
        s = event.pos()
        self.setMouseTracking(True)
        self.Warning.append('X:' + str(s.x()))
        self.Warning.append('Y:' + str(s.y()))

        desktop = QtWidgets.QApplication.desktop()

        Rows = 20
        Cols = 6
        width = desktop.width() * 0.9
        height = desktop.height() * 0.9
        wstep = width / Cols
        hstep = height / Rows
        if s.x() < 2 * wstep and s.y() > 12 * hstep:
            self.resizeDP1(self.MainWindow)

        if s.x() > 4 * wstep and s.y() < 6 * hstep:
            self.resizeDP(self.MainWindow)

    def resizeDP1(self, window):
        desktop = QtWidgets.QApplication.desktop()

        Rows = 20
        Cols = 6
        width = desktop.width() * 0.9
        height = desktop.height() * 0.9
        wstep = width / Cols
        hstep = height / Rows

        w = 0.99 * wstep
        h = 0.94 * hstep

        self.shot.setGeometry(0 * wstep, 0 * h, 0.5* w, 1 * h)
        self.shotOK.setGeometry(0 * wstep, 1 * h, 0.5 * w, 1 * h)
        self.draw.setGeometry(0 * wstep, 2 * h, 0.5 * w, 1 * h)

        self.xLeft.setGeometry(0.5 * wstep, 0 * h, 0.5* w, 1 * h)
        self.update.setGeometry(0.5 * wstep, 1 * h, 0.5 * w, 1 * h)
        self.chnlPattern.setGeometry(0.5 * wstep, 2 * h, 0.5 * w, 1 * h)

        self.xRight.setGeometry(1.0 * wstep, 0 * h, 0.5* w, 1 * h)

        self.freqInterp.setGeometry(1.5 * wstep, 0 * h, 0.5* w, 1 * h)

        self.clearAll.setGeometry(2.0 * wstep, 0 * h, 0.5 * w, 1 * h)
        self.Warning.setGeometry(0.01 * wstep, 3 * h, 2.99 * w, 9.2 * h)

        self.LabelFiles.setGeometry(3 * wstep, 0 * h, 0.99 * w, 1 * h)
        self.LabelCurves.setGeometry(4 * wstep, 0 * h, 0.99 * w, 1 * h)
        self.Browser.setGeometry(5 * wstep, 0 * h, 0.99 * w, 1 * h)
        self.Files.setGeometry(3 * wstep, 1 * h, 0.99 * w, 7.2 * h)
        self.Curves.setGeometry(4 * wstep, 1 * h, 0.99 * w, 7.2 * h)
        self.Channels.setGeometry(5 * wstep, 1 * h, 0.99 * w, 7.2 * h)
        self.groupBox.setGeometry(0.4, 8 * h, 6.03 * w, 12.5 * h)

    def resizeDP(self, window):
        window.move(window.width() * -2, 0)  # 先将窗口放到屏幕外，可避免移动窗口时的闪烁现象。
        desktop = QtWidgets.QApplication.desktop()

        Rows = 20
        Cols = 6
        width = desktop.width() * 0.9
        height = desktop.height() * 0.9
        wstep = width / Cols
        hstep = height / Rows

        w = 0.99 * wstep
        h = 0.94 * hstep

        window.resize(width, height)
        x = (desktop.width() - window.frameSize().width()) // 2
        y = (desktop.height() - window.frameSize().height()) // 2
        window.move(x, y - 30)
        window.show()

        self.shot.setGeometry(0 * wstep, 0 * h, 0.5* w, 1 * h)
        self.shotOK.setGeometry(0 * wstep, 1 * h, 0.5 * w, 1 * h)
        self.draw.setGeometry(0 * wstep, 2 * h, 0.5 * w, 1 * h)

        self.xLeft.setGeometry(0.5 * wstep, 0 * h, 0.5* w, 1 * h)
        self.update.setGeometry(0.5 * wstep, 1 * h, 0.5 * w, 1 * h)
        self.chnlPattern.setGeometry(0.5 * wstep, 2 * h, 0.5 * w, 1 * h)

        self.xRight.setGeometry(1.0 * wstep, 0 * h, 0.5* w, 1 * h)

        self.freqInterp.setGeometry(1.5 * wstep, 0 * h, 0.5* w, 1 * h)

        self.clearAll.setGeometry(2.0 * wstep, 0 * h, 0.5 * w, 1 * h)
        self.Warning.setGeometry(0.01 * wstep, 3 * h, 2.99 * w, 9.2 * h)

        self.LabelFiles.setGeometry(3 * wstep, 0 * h, 0.99 * w, 1 * h)
        self.LabelCurves.setGeometry(4 * wstep, 0 * h, 0.99 * w, 1 * h)
        self.Browser.setGeometry(5 * wstep, 0 * h, 0.99 * w, 1 * h)
        self.Files.setGeometry(3 * wstep, 1 * h, 0.99 * w, 19.5 * h)
        self.Curves.setGeometry(4 * wstep, 1 * h, 0.99 * w, 19.5 * h)
        self.Channels.setGeometry(5 * wstep, 1 * h, 0.99 * w, 19.5 * h)
        self.groupBox.setGeometry(0.2, 12 * h, 3 * w, 8.5 * h)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.shotOK.setText(_translate("MainWindow", "shotOK"))
        self.draw.setText(_translate("MainWindow", "draw"))
        self.LabelFiles.setText(_translate("MainWindow", "Files"))
        self.LabelCurves.setText(_translate("MainWindow", "Curves"))
        self.Browser.setText(_translate("MainWindow", "Browser"))
        self.groupBox.setTitle(_translate("MainWindow", "GroupBox"))
        self.clearAll.setText(_translate("MainWindow", "clearAll"))
        self.update.setText(_translate("MainWindow", "update"))


from collections import Counter
from itertools import groupby

from .save_output import SaveOutput

OPERATIONS = ("add", "sub", "mult", "div", "mod", "pow", "floordiv", # arithmetic operators
              "add_assign", "sub_assign", "mult_assign", "div_assign", # assignment operators 1
              "mod_assign", "pow_assign", "floordiv_assign", # assignment operators 2
              "bitand_assign", "bitor_assign", "bitxor_assign", # assignment operators 3
              "rshift_assign", "lshift_assign", # assignment operators 4
              "eq", "noteq", "gt", "lt", "gte", "lte", # comparison operators
              "and", "or", "not", # logical operators
              "is", "isnot", # identity operators
              "in", "notin", # membership operators
              "bitand", "bitor", "bitxor", "invert", "rshift", "lshift" # bitwise operators
             )

def escape_parentheses(string):
    return string.replace("(", r"\(").replace(")", r"\)")

def entity_name(evaluation):
    component = evaluation.code_component
    ent_name_str = ""

    if component.type in ("name", "literal", "param"):
        ent_name_str = str(component.first_char_line) + "_" + component.name
    elif component.type == "subscript":
        ent_name = component.name.split("[")[0]
        ent_name += "@" + component.name.split("[")[1].split("]")[0]
        ent_name_str = str(component.first_char_line) + "_" + ent_name
    else:
        ent_name_str = component.type + str(component.id)

    return escape_parentheses(ent_name_str)

def entity_type(evaluation):
    component = evaluation.code_component

    if component.type in OPERATIONS:
        return "eval"
    elif component.type == "call":
        return "eval"
    elif component.type == "subscript":
        return "access"
    else:
        return component.type

def is_int(value):
    try:
        int(value)
        return True
    except ValueError:
        return False

def is_float(value):
    try:
        float(value)
        return True
    except ValueError:
        return False

def export_prov(trial, name="temp", formats="svg"):
    output = SaveOutput(name=name, formats=formats)
    output("prefix script <https://dew-uff.github.io/versioned-prov/ns/script#>")
    output("prefix version <https://dew-uff.github.io/versioned-prov/ns#>\n")
    ckpt_list = []
    assignments = {}
    entity_generated_by_activity = []

    def insert_ckpt(ckpt):
        if ckpt not in ckpt_list:
            ckpt_list.append(ckpt)

    def get_ckpt_order(ckpt):
        return ckpt_list.index(ckpt) + 1

    def entity_name_by_id(evaluation_id):
        for ev in trial.evaluations:
            if ev.id == evaluation_id:
                return entity_name(ev)

    def activity_name(evaluation_id):
        for ev in trial.evaluations:
            if ev.id == evaluation_id:
                return ev.code_component.type

    def activity_label(evaluation_id):
        for ev in trial.evaluations:
            if ev.id == evaluation_id:
                return ev.code_component.name.split("(")[0]

    def get_ckpt_by_id(evaluation_id):
        for ev in trial.evaluations:
            if ev.id == evaluation_id:
                return ev.checkpoint

    def find_collection_name(evaluation_id):
        for dep in trial.dependencies:
            if dep.dependent_id == evaluation_id and dep.type == "value":
                dependency = entity_name(dep.dependency)
                if dependency in assignments:
                    dependency = assignments[dependency]
                return dependency
        return None

    for act in trial.activations:
        insert_ckpt(act.start_checkpoint)

    for ev in trial.evaluations:
        insert_ckpt(ev.checkpoint)

    for mem in trial.members:
        insert_ckpt(mem.checkpoint)

    ckpt_list.sort()
    counter = Counter()

    for ev in trial.evaluations:
        if ev.activation_id != 0 and not(ev.code_component.type == "name" and ev.code_component.mode == "r"):
            value = ev.repr

            if not is_int(value) and is_float(value):
                value += "f"

            entity_str = 'entity({}, [value="{}", type="script:{}"'.format(
                entity_name(ev),
                value,
                entity_type(ev)
            )

            if ev.code_component.type == ("literal"):
                entity_str += '])'
            else:
                entity_str += ', label="{}"])'.format(ev.code_component.name)

            output(entity_str)

    output()

    collection_name = ""
    previous_dep_id = 0
    previous_type = ""
    previous_activity = ""
    groups = groupby(trial.dependencies, key=lambda x: (x.dependent_id, x.type))
    for (dep_id, type_), group in groups:
        if type_ == "assignment":
            for dep in group:
                key = entity_name(dep.dependent)
                value = entity_name(dep.dependency)
                assignments[key] = value
        elif type_ == "argument" and activity_name(dep_id) != "param":
            act_name = activity_name(dep_id)
            counter[act_name] += 1
            act_type = act_name
            act_label = activity_label(dep_id)
            activity_str = 'activity({}{}, [type="script:{}", label="{}"])'.format(
                act_name,
                counter[act_name],
                act_type,
                act_label
            )
            output(activity_str)
            previous_activity = act_name + str(counter[act_name])

            for dep in group:
                dependency = entity_name(dep.dependency)

                if dependency in assignments:
                    dependency = assignments[dependency]

                used_str = 'used({}{}, {}, -,[version:checkpoint="{}"])'.format(
                    act_name,
                    counter[act_name],
                    dependency,
                    get_ckpt_order(dep.dependency.checkpoint)
                )
                output(used_str)

            ent_act = entity_name_by_id(dep_id) + act_name + str(counter[act_name])
            if ent_act not in entity_generated_by_activity:
                wasGeneratedBy_str = 'wasGeneratedBy({}, {}{}, -,[version:checkpoint="{}"])'.format(
                    entity_name_by_id(dep_id),
                    act_name,
                    counter[act_name],
                    get_ckpt_order(get_ckpt_by_id(dep_id))
                )
                output(wasGeneratedBy_str)

            output()
        elif type_ == "value" or type_ == "slice":
            for dep in group:
                using_activity = previous_activity

                if type_ == "value" and not(previous_dep_id == dep_id and previous_type == "assign"):
                    using_activity = "access" + str(counter["access"] + 1)
                    previous_activity = using_activity

                dependency = entity_name(dep.dependency)

                if dependency in assignments:
                    dependency = assignments[dependency]

                used_str = 'used({}, {}, -'.format(
                    using_activity,
                    dependency
                )

                if type_ == "value":
                    used_str += ', [version:checkpoint="{}"]'.format(
                        get_ckpt_order(dep.dependency.checkpoint)
                    )
                    collection_name = dependency

                used_str += ')'
                output(used_str)
        elif type_ != "item" and type_ != "dependency":
            counter["g"] += 1
            act_name = type_
            act_type = type_

            if type_ == "use":
                act_name = activity_name(dep_id)

                if act_name in OPERATIONS:
                    act_type = "operation"
            elif type_ in OPERATIONS:
                act_type = "operation"

            if act_type != "use":
                counter[act_name] += 1
                activity_str = 'activity({}{}, [type="script:{}"])'.format(
                    act_name,
                    counter[act_name],
                    act_type
                )
                output(activity_str)
                previous_activity = act_name + str(counter[act_name])

            for dep in group:
                counter["u"] += 1
                dependent = entity_name(dep.dependent)
                dependency = entity_name(dep.dependency)
                count_act_name = counter[act_name]

                if dependency in assignments:
                    dependency = assignments[dependency]

                if act_name == "call" and act_type == "use":
                    count_act_name = counter[act_name] + 1
                    entity_generated_by_activity.append(dependent + "call" + str(count_act_name))

                wasDerivedFrom_str = 'wasDerivedFrom({}, {}, {}{}, g{}, u{}, ['.format(
                    dependent,
                    dependency,
                    act_name,
                    count_act_name,
                    counter["g"],
                    counter["u"],
                )

                if dep.reference == 1:
                    wasDerivedFrom_str += 'type="version:Reference", '

                wasDerivedFrom_str += 'version:checkpoint="{}"'.format(
                    get_ckpt_order(dep.dependent.checkpoint)
                )

                if type_ == "access":
                    wasDerivedFrom_str += ', version:collection="{}", version:key="{}", version:access="{}"'.format(
                        collection_name,
                        dep.key[1:-1],
                        dep.dependent.code_component.mode
                    )
                elif entity_type(dep.dependent) == "access":
                    wasDerivedFrom_str += ', version:collection="{}", version:key="{}", version:access="{}"'.format(
                        find_collection_name(dep.dependent_id),
                        entity_name(dep.dependent).split("@")[1],
                        "w"
                    )

                wasDerivedFrom_str += '])'
                output(wasDerivedFrom_str)

            output()

        previous_dep_id = dep_id
        previous_type = type_

    for mem in trial.members:
        if mem.collection_activation_id and mem.member_activation_id:
            member = entity_name(mem.member)

            if member in assignments:
                member = assignments[member]

            hadMember_str = 'hadMember({}, {}, [type="version:Put", version:key="{}", version:checkpoint="{}"])'.format(
                entity_name(mem.collection),
                member,
                mem.key[1:-1],
                get_ckpt_order(mem.checkpoint)
            )
            output(hadMember_str)

    return output


#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import uuid
from typing import Dict, List, Tuple, Any
from app import db
from sqlalchemy.dialects.postgresql import JSONB, UUID, ARRAY
from sqlalchemy import func, or_, and_
from flask import g

def get_session():
    return db.create_scoped_session(options={"autocommit": False, "autoflush": False})

session = get_session()

class BaseMixIn(object):
    # id = db.Column(db.Integer, primary_key=True)
    # todo 建模下未添加字段唯一索引
    uuid = db.Column(
        UUID(as_uuid=True), unique=True, default=uuid.uuid4, primary_key=True
    )
    creator_uuid = db.Column(db.String(50), nullable=True)
    creator_ugid = db.Column(db.String(50), nullable=True)
    create_time = db.Column(db.DateTime(), default=datetime.datetime.now)
    modify_time = db.Column(
        db.DateTime(), default=datetime.datetime.now, onupdate=datetime.datetime.now
    )
    meta_info = db.Column(JSONB, nullable=True)
    is_delete = db.Column(db.Integer, nullable=True, default=0)
    version_id = db.Column(db.Integer, nullable=True, default=0)

    @classmethod
    def gen_version_id(cls, cls_uuid):
        return (
            session.query(func.max(cls.version_id))
            .filter(cls.uuid == cls_uuid)
            .scalar()
            or 0
        ) + 1

    @classmethod
    def get_by_uuid(cls, cls_uuid):
        return session.query(cls).filter(cls.uuid == cls_uuid).scalar()

    @property
    def creator_user(self):
        data = None
        if data:
            return {"user_id": self.creator_uuid, "user_name": data["username"]}
        else:
            return {"user_id": self.creator_uuid, "user_name": ""}

    @property
    def creator_group(self):
        data = None
        if data:
            return {"group_id": self.creator_ugid, "group_name": data["group_name"]}
        else:
            return {"group_id": self.creator_ugid, "group_name": ""}

    def to_dict(self):
        return {c.name: c.type for c in self.__table__.columns}

class Unit:
    UNIT_TYPE_UNKNOWN = 0
    UNIT_TYPE_ROBOT = 1
    UNIT_TYPE_STATION = 2
    UNIT_TYPE_ELEVATOR = 3
    UNIT_TYPE_GATE = 4
    UNIT_TYPE_AUTO_DOOR = 5
    UNIT_TYPE_IOT_GENERAL = 6
    UNIT_TYPE_CHARGER = 10
    UNIT_TYPE_CALL = 11

class Direction:
    DIRECTION_UNKNOWN = 0
    DIRECTION_NO_DIRECTION = 1
    DIRECTION_IN = 2
    DIRECTION_OUT = 3
    DIRECTION_BIDIRECTIONAL = 4

class Site(db.Model, BaseMixIn):
    __tablename__: str = "site"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    SITE_STATUS_UNKNOWN = 0
    SITE_STATUS_NORMAL = 1
    SITE_STATUS_MAINTENANCE = 10
    SITE_STATUS_DISABLED = 20

    BUSINESS_TYPE_UNKNOWN = 0
    BUSINESS_TYPE_CBD = 1
    BUSINESS_TYPE_HOTEL = 2
    BUSINESS_TYPE_KTV = 3
    # map file key in meta info
    MAP_FILE_DOWNLOAD_KEY = "map_file_url"

    site_uid = db.Column(db.Integer, nullable=False)
    name = db.Column(db.String(128), nullable=False, default="")
    address = db.Column(db.Text, nullable=False, default="")
    status = db.Column(db.SmallInteger, nullable=False, default=0)
    has_building_connector = db.Column(db.Boolean, nullable=False, default=True)
    business_types = db.Column(ARRAY(db.Integer), nullable=False, default=[])
    location = db.Column(db.String(128), nullable=False, default="")

    section_site = db.Column(JSONB, nullable=False, default={})
    section_building = db.Column(JSONB, nullable=False, default={})
    section_map = db.Column(JSONB, nullable=False, default={})
    section_facility = db.Column(JSONB, nullable=False, default={})
    section_iot = db.Column(JSONB, nullable=False, default={})

    @classmethod
    def encode_business_type(cls, type_str: str) -> int:
        mapping = {
            "BUSINESS_TYPE_CBD": cls.BUSINESS_TYPE_CBD,
            "BUSINESS_TYPE_HOTEL": cls.BUSINESS_TYPE_HOTEL,
            "BUSINESS_TYPE_KTV": cls.BUSINESS_TYPE_KTV,
        }
        return mapping.get(type_str, cls.BUSINESS_TYPE_UNKNOWN)

    @classmethod
    def decode_business_type(cls, bussiness_type: int) -> str:
        mapping = {
            cls.BUSINESS_TYPE_CBD: "BUSINESS_TYPE_CBD",
            cls.BUSINESS_TYPE_HOTEL: "BUSINESS_TYPE_HOTEL",
            cls.BUSINESS_TYPE_KTV: "BUSINESS_TYPE_KTV",
        }
        return mapping.get(bussiness_type, "BUSINESS_TYPE_UNKNOWN")

    @classmethod
    def encode_site_status(cls, type_str: str) -> int:
        mapping = {
            "SITE_STATUS_DISABLED": cls.SITE_STATUS_DISABLED,
            "SITE_STATUS_NORMAL": cls.SITE_STATUS_NORMAL,
            "SITE_STATUS_MAINTENANCE": cls.SITE_STATUS_MAINTENANCE,
        }
        return mapping.get(type_str, cls.SITE_STATUS_UNKNOWN)

    @classmethod
    def decode_site_status(cls, status: int) -> str:
        mapping = {
            cls.SITE_STATUS_DISABLED: "SITE_STATUS_DISABLED",
            cls.SITE_STATUS_NORMAL: "SITE_STATUS_NORMAL",
            cls.SITE_STATUS_MAINTENANCE: "SITE_STATUS_MAINTENANCE",
        }
        return mapping.get(status, "SITE_STATUS_UNKNOWN")

class Building(db.Model, BaseMixIn):
    __tablename__: str = "building"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True))

    name = db.Column(db.String(128), nullable=False, default="")
    address = db.Column(db.String(128), nullable=False, default="")
    building_floors = db.Column(JSONB, nullable=False, default=[])
    elevators = db.Column(JSONB, nullable=False, default=[])
    chargers = db.Column(JSONB, nullable=False, default=[])
    stations = db.Column(JSONB, nullable=False, default=[])
    auto_doors = db.Column(JSONB, nullable=False, default=[])
    gates = db.Column(JSONB, nullable=False, default=[])

    def get_building_info(self):
        return {
            "uuid": str(self.uuid),
            "name": self.name,
            "address": self.address,
            "building_floors": self.get_building_floors_info(),
            "elevators": self.get_elevators_info(),
            "elevator_groups": self.get_elevator_group(),
            "charger_groups": self.get_charger_info(),
            "station_groups": self.get_station_info(),
            "auto_door_groups": self.get_auto_door_info(),
            "gate_groups": self.get_gate_info(),
        }

    def get_building_floors_info(self):
        """Keep order based on building_floors
        :return:
        """

        def get_connect_building_floor_uuid(floor_uuid: str):
            connect_building_floor_uuid_list = []
            connects = (
                session.query(BuildingFloorConnector)
                .filter(BuildingFloorConnector.is_delete == 0)
                .filter(
                    # 只查主关联侧
                    BuildingFloorConnector.floor_uuid_1 == uuid.UUID(floor_uuid),
                    # BuildingFloorConnector.floor_uuid_2 == uuid.UUID(floor_uuid),
                )
            ).all()
            for c in connects:
                connect_building_floor_uuid_list.append(c.floor_uuid_2)

            return connect_building_floor_uuid_list

        query = (
            session.query(BuildingFloor)
            .filter(BuildingFloor.building_uuid == self.uuid)
            .order_by(BuildingFloor.create_time)
            .all()
        )
        bfloors = {str(floor.uuid): floor for floor in query}

        # TODO change to SystemError
        assert len(bfloors) == len(self.building_floors)

        info = []
        for _uuid in self.building_floors:
            bfloor: BuildingFloor = bfloors[_uuid]
            connect_building_floor_uuid_list = get_connect_building_floor_uuid(_uuid)
            if connect_building_floor_uuid_list:
                for connect in connect_building_floor_uuid_list:
                    if str(connect) != _uuid:
                        info.append(
                            {
                                "uuid": _uuid,
                                "name": bfloor.name,
                                "connected_building_floor_uuid": str(connect),
                            }
                        )
            else:
                info.append(
                    {
                        "uuid": _uuid,
                        "name": bfloor.name,
                        "connected_building_floor_uuid": "",
                    }
                )

        return info

    def get_elevators_info(self):
        """Keep order based on elevators
        """
        query = (
            session.query(Elevator).filter(Elevator.building_uuid == self.uuid).all()
        )

        belevators = {str(elevator.uuid): elevator for elevator in query}

        # TODO change to SystemError
        assert len(belevators) == len(self.elevators)

        info = []
        for _uuid in self.elevators:
            belevator: Elevator = belevators[_uuid]
            info.append(
                {
                    "uuid": str(belevator.uuid),
                    "name": belevator.name,
                    "brand": belevator.brand,
                    "elevator_floors": belevator.get_elevator_floors_info(),
                }
            )
        return info

    def get_facility_group(self, unit_type: int):
        """Keep order based on elevators
        """
        query = (
            session.query(SiteGroup)
            .filter(SiteGroup.building_uuid == self.uuid)
            .filter(SiteGroup.unit_type == unit_type)
            .order_by(SiteGroup.create_time)
            .all()
        )

        info = []
        for site_group in query:
            group = site_group.get_site_group_info()
            if group:
                info.append(group)
        return info

    def get_auto_door_info(self):
        return self.get_facility_group(Unit.UNIT_TYPE_AUTO_DOOR)

    def get_gate_info(self):
        return self.get_facility_group(Unit.UNIT_TYPE_GATE)

    def get_charger_info(self):
        return self.get_facility_group(Unit.UNIT_TYPE_CHARGER)

    def get_station_info(self):
        return self.get_facility_group(Unit.UNIT_TYPE_STATION)

    def get_elevator_group(self):
        return self.get_facility_group(Unit.UNIT_TYPE_ELEVATOR)

class BuildingFloor(db.Model, BaseMixIn):
    __tablename__: str = "building_floor"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True))
    building_uuid = db.Column(UUID(as_uuid=True))

    name = db.Column(db.String(128), nullable=False, default="")
    floor_index = db.Column(db.Integer, nullable=False, default=0)
    connected_floors = db.Column(JSONB, nullable=False, default=[])
    floor_facilities = db.Column(JSONB, nullable=False, default=[])

    def get_building_floor_info(self):
        # map = session().query(Map).filter(Map.building_floor_uuid == self.uuid).first()
        building_floor_info = {
            "uuid": str(self.uuid),
            "name": self.name,
            "floor_index": self.floor_index,
        }
        # if map:
        #     building_floor_info["map_sid"] = map.map_sid
        return building_floor_info

class BuildingFloorConnector(db.Model, BaseMixIn):
    __tablename__: str = "building_floor_connector"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True))

    building_uuid_1 = db.Column(UUID(as_uuid=True))
    floor_uuid_1 = db.Column(UUID(as_uuid=True))
    building_uuid_2 = db.Column(UUID(as_uuid=True))
    floor_uuid_2 = db.Column(UUID(as_uuid=True))

    @classmethod
    def is_floor_connect_exist(cls, floor_uuid_1, floor_uuid_2) -> list:
        # floor_uuid_1 作为主关联侧  floor_uuid_2作为被关联方
        # 但是不允许 floor_uuid_1 floor_uuid_2 关联两次  即使位置不同
        return (
            session.query(cls)
            .filter(cls.is_delete == 0)
            .filter(
                or_(
                    and_(
                        cls.floor_uuid_1 == floor_uuid_1,
                        cls.floor_uuid_2 == floor_uuid_2,
                    ),
                    and_(
                        cls.floor_uuid_1 == floor_uuid_2,
                        cls.floor_uuid_2 == floor_uuid_1,
                    ),
                )
            )
        ).all()

class Elevator(db.Model, BaseMixIn):
    __tablename__: str = "elevator"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True))
    building_uuid = db.Column(UUID(as_uuid=True))

    name = db.Column(db.String(128), nullable=False, default="")
    brand = db.Column(db.String(128), nullable=False, default="")
    elevator_floors = db.Column(JSONB, nullable=False, default=[])
    group_uuid = db.Column(UUID(as_uuid=True))

    def get_elevator_floors_info(self):
        """Keep elevator floors order based on elevator_floors
        :return:
        """
        query = (
            session.query(ElevatorFloor)
            .filter(ElevatorFloor.elevator_uuid == self.uuid)
            .all()
        )
        efloors = {str(efloor.uuid): efloor for efloor in query}
        info = []
        for _uuid in self.elevator_floors:
            efloor: ElevatorFloor = efloors[_uuid]
            info.append(
                {
                    "uuid": str(efloor.uuid),
                    "name": efloor.name,
                    "building_floor_uuid": str(efloor.building_floor_uuid or ""),
                }
            )
        return info

class ElevatorFloor(db.Model, BaseMixIn):
    __tablename__: str = "elevator_floor"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True))
    building_uuid = db.Column(UUID(as_uuid=True))
    elevator_uuid = db.Column(UUID(as_uuid=True))

    floor_index = db.Column(db.Integer, nullable=False, default=0)
    name = db.Column(db.String(128), nullable=False, default="")
    building_floor_uuid = db.Column(UUID(as_uuid=True))
    is_reachable = db.Column(db.Boolean, nullable=False, default=False)

class FloorFacility(db.Model, BaseMixIn):
    __tablename__: str = "floor_facility"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True))

    name = db.Column(db.String(128), nullable=False, default="")
    unit_type = db.Column(db.SmallInteger, nullable=False)
    direction = db.Column(db.SmallInteger, nullable=False, default=0)
    building_uuid = db.Column(UUID(as_uuid=True))
    group_uuid = db.Column(UUID(as_uuid=True))
    building_floor_uuid = db.Column(UUID(as_uuid=True))

    def get_floor_facility_info(self):
        return {
            "uuid": str(self.uuid),
            "name": self.name,
            "direction": self.direction,
            "unit_type": self.unit_type,
            "building_uuid": str(self.building_uuid or ""),
            "building_floor_uuid": str(self.building_floor_uuid or ""),
        }

class SiteGroup(db.Model, BaseMixIn):
    __tablename__: str = "site_group"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True))
    building_uuid = db.Column(UUID(as_uuid=True), nullable=True)
    building_floor_uuid = db.Column(UUID(as_uuid=True))

    name = db.Column(db.String(128), nullable=False, default="")
    facility_group_sid = db.Column(db.Integer)
    unit_type = db.Column(db.SmallInteger, nullable=False, default=0)
    members = db.Column(JSONB, nullable=False, default=[])

    def get_members_attr(self):
        type_cls_dict = {
            Unit.UNIT_TYPE_GATE: FloorFacility,
            Unit.UNIT_TYPE_AUTO_DOOR: FloorFacility,
            Unit.UNIT_TYPE_CHARGER: FloorFacility,
            Unit.UNIT_TYPE_STATION: FloorFacility,
            Unit.UNIT_TYPE_ELEVATOR: Elevator,
            Unit.UNIT_TYPE_ROBOT: Robot,
        }

        cls = type_cls_dict[self.unit_type]
        # elevator、robot 没有building floor uuid 、 unit_type
        # robot 只有name

        units = (
            session.query(SiteFacilityUnit)
            .filter(SiteFacilityUnit.facility_uuid.in_(self.members))
            .all()
        )
        facility_unit_dict = {str(i.facility_uuid): i for i in units}

        if cls == FloorFacility:
            query = (
                session.query(
                    cls.name,
                    cls.uuid,
                    cls.direction,
                    cls.unit_type,
                    cls.building_uuid,
                    cls.building_floor_uuid,
                )
                .filter(cls.uuid.in_(self.members))
                .order_by(cls.create_time)
                .all()
            )

            return [
                {
                    "name": i.name,
                    "uuid": str(i.uuid),
                    "direction": i.direction,
                    "unit_type": i.unit_type,
                    "building_uuid": str(i.building_uuid),
                    "unit_name": facility_unit_dict[str(i.uuid)].unit_name or "",
                    "unit_uid": facility_unit_dict[str(i.uuid)].unit_uid or 0,
                    "unit_uuid": str(facility_unit_dict[str(i.uuid)].unit_uuid or ""),
                    "building_floor_uuid": str(i.building_floor_uuid or ""),
                }
                for i in query
            ]
        if cls == Elevator or cls == Robot:
            query = (
                session.query(cls.name, cls.uuid)
                .filter(cls.uuid.in_(self.members))
                .order_by(cls.create_time)
                .all()
            )
            return [
                {
                    "name": i.name,
                    "uuid": str(i.uuid),
                    "unit_name": facility_unit_dict[str(i.uuid)].unit_name or "",
                    "unit_uid": facility_unit_dict[str(i.uuid)].unit_uid or 0,
                    "unit_uuid": str(facility_unit_dict[str(i.uuid)].unit_uuid or ""),
                }
                for i in query
            ]

    def get_site_group_info(self):
        group = {
            "uuid": str(self.uuid),
            "name": self.name,
            "building_floor_uuid": str(self.building_floor_uuid or ""),
            "unit_type": self.unit_type,
            "members": self.get_members_attr(),
        }
        if self.unit_type in [Unit.UNIT_TYPE_ROBOT, Unit.UNIT_TYPE_ELEVATOR]:
            del group["building_floor_uuid"]
        return group

class Robot(db.Model, BaseMixIn):
    __tablename__: str = "robot"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    ROBOT_TYPE_UNKNOWN = 0
    ROBOT_TYPE_DELIVERY = 10
    ROBOT_TYPE_STERILIZATION = 20

    ROBOT_HOME_POI_KEY = "home_point_poi"

    site_uuid = db.Column(UUID(as_uuid=True))
    robot_type = db.Column(db.SmallInteger, nullable=False, default=0)
    group_uuid = db.Column(UUID(as_uuid=True))
    name = db.Column(db.String(128), nullable=False, default="")

    def get_robot_info(self):
        sfu: SiteFacilityUnit = session.query(SiteFacilityUnit).filter(
            SiteFacilityUnit.facility_uuid == self.uuid
        ).scalar()
        return {
            "uuid": self.uuid,
            "name": self.name,
            "unit_uid": sfu.unit_uid,
            "facility_sid": sfu.facility_sid,
            "robot_type": self.robot_type,
        }

class SiteFacilityUnit(db.Model, BaseMixIn):
    __tablename__: str = "site_facility_unit"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    site_uuid = db.Column(UUID(as_uuid=True), nullable=False)
    site_uid = db.Column(db.BigInteger, nullable=False)

    facility_uuid = db.Column(UUID(as_uuid=True))
    group_uuid = db.Column(UUID(as_uuid=True))
    facility_sid = db.Column(db.Integer, default=0)
    facility_group_index = db.Column(db.Integer, default=0)
    unit_type = db.Column(db.Integer, nullable=False)
    unit_uuid = db.Column(UUID(as_uuid=True), unique=True, nullable=True)
    unit_uid = db.Column(db.BigInteger, unique=True, nullable=True)
    unit_name = db.Column(db.String, nullable=True)

    def get_facility_name(self, facility_uuid) -> str:
        if self.unit_type == Unit.UNIT_TYPE_ELEVATOR:
            cls = Elevator
        elif self.unit_type == Unit.UNIT_TYPE_ROBOT:
            cls = Robot
        else:
            cls = FloorFacility

        facility = session.query(cls).filter(cls.uuid == facility_uuid).scalar()
        if facility is not None:
            return facility.name

    def get_facility_unit_info(self):
        return {
            str(self.uuid): {
                "site_uid": self.site_uid,
                "site_uuid": str(self.site_uuid),
                "facility_name": self.get_facility_name(self.facility_uuid),
                "facility_uuid": str(self.facility_uuid),
                "group_uuid": str(self.group_uuid),
                "unit_type": self.unit_type,
                "unit_uuid": str(self.unit_uuid or ""),
                "unit_uid": self.unit_uid or 0,
                "unit_name": self.unit_name or "",
            }
        }

    def get_site_info(self):
        site_group: SiteGroup = (
            session.query(SiteGroup).filter(SiteGroup.uuid == self.group_uuid).first()
        )
        if not site_group:
            # SiteGroupNotFound
            raise

        return {
            "site_uuid": str(self.site_uuid),
            "site_uid": self.site_uid,
            "unit_type": self.unit_type,
            "unit_uuid": str(self.unit_uuid) if self.unit_uuid else None,
            "unit_uid": self.unit_uid,
            "unit_sid": self.facility_sid,
            "unit_group_sid": site_group.facility_group_sid,
            "unit_group_index": self.facility_group_index,
            "unit_name": self.unit_name,
        }

    @classmethod
    def get_bind_unit_uuid_list(cls, unit_type: int) -> list:
        unit_uuids = (
            session.query(cls.unit_uuid)
            .filter(cls.unit_type == unit_type)
            .filter(cls.unit_uuid != None)
            .all()
        )
        return [str(i[0]) for i in unit_uuids]

    @classmethod
    def query_by_unit_uuid(cls, unit_uuid: str):
        return session.query(cls).filter(cls.unit_uuid == unit_uuid).first()

class Cmdb(db.Model, BaseMixIn):
    # 资产管理 包含绑定信息 绑定站点 绑定状态
    __tablename__: str = "cmdb"
    __table_args__: Dict[str, Any] = {"schema": "public"}

    # 站点信息可空  非空则表示已绑定
    site_uuid = db.Column(UUID(as_uuid=True))
    site_uid = db.Column(db.BigInteger)
    # 所绑定的站点设施
    facility_uuid = db.Column(UUID(as_uuid=True))

    unit_type = db.Column(db.Integer, nullable=False)

    unit_uuid = db.Column(UUID(as_uuid=True), unique=True, nullable=True)
    unit_uid = db.Column(db.BigInteger, unique=True, nullable=True)
    # 资产名称
    unit_name = db.Column(db.String, nullable=True)

    def get_unit_info(self):
        return {
            # "site_uuid": str(self.site_uuid) if self.site_uuid else self.site_uuid,
            # "site_uid": self.site_uid,
            "unit_type": self.unit_type,
            "unit_uuid": str(self.unit_uuid),
            "unit_uid": self.unit_uid,
            "unit_name": self.unit_name,
        }


"""Lumize DMX Engine 2 TCP connection handling module"""
import socket
import threading
import multiprocessing
import asyncio

from types import FunctionType

# Configuration constants
WELCOME_MESSAGE = b"Lumize DMX Engine v2.0\n"
CONNECTION_CHECK_EXPECTED_RESPONSE: str = "ok"
CONNECTION_CHECK_MESSAGE: str = "conncheck"

# Exception types
class ReconnectError(Exception):
    """Error in reconnecting to Lumize DMX Engine 2"""

class NotConnected(Exception):
    """Tried sending command but connection to Lumize DMX Engine 2 can't be enstablished"""

class TcpConnection:
    """Class that represents a TCP connection to the Lumize DMX Engine 2"""

    def __init__(
        self,
        host: str,
        port: int,
        ext_logger: FunctionType,
        keep_alive: int,
    ) -> None:
        self.__host: str = host
        self.__port: int = port
        self.__keep_alive_interval = keep_alive
        self.__run_keep_alive = keep_alive > 0  # If keep_alive is 0s, don't run

        # Setup print as logger if no external logger function is provided
        if ext_logger is None:
            self.__logger = print
        else:
            self.__logger = ext_logger

        # Setup state variables
        self.__running: bool = True
        self.__is_connected: bool = False

        self.__keep_alive_cv = multiprocessing.Condition()
        self.__keep_alive_thread = threading.Thread(target=self.__keep_alive)

        # Init socket and respective lock
        self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__socket_lock = threading.Lock()

    @property
    def host(self) -> int:
        """Returns hostname of the engine this connections refers to"""
        return self.__host

    def start(self) -> None:
        """Starts the connection"""
        try:
            self.__reconnect()
        except ReconnectError:
            self.__logger("[TCP] First connection unsuccesful")

        # Start keep alive thread if configured
        if self.__run_keep_alive:
            self.__keep_alive_thread.start()

    def stop(self) -> None:
        """Stops the connection"""
        self.__running = False

        if self.__run_keep_alive:
            # Notify connection checker that we want to exit immediately
            with self.__keep_alive_cv:
                self.__keep_alive_cv.notify()

            # Wait for conneciton checker thread to finish execution
            self.__keep_alive_thread.join()

        self.__logger("[TCP] Closing connection...")

        # Close socket
        try:
            self.__socket.close()
        except socket.error:
            pass

    def is_ok(self) -> bool:
        """Is the connection ok"""
        return self.__is_connected

    def __reconnect(self):
        self.__logger(
            f"[TCP] Attepting connection to {self.__host}, port: {self.__port}"
        )

        # Lock socket mutex
        with self.__socket_lock:
            try:
                # Create socket
                self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

                # Connect to address
                self.__socket.connect((self.__host, self.__port))

                # Read welcome message
                self.__socket.settimeout(5)  # Set timeout to receive welcome message
                received_message: bytes = self.__socket.recv(len(WELCOME_MESSAGE) + 5)

            except socket.error as error:
                self.__logger(f"[TCP] Socket error while connecting: {error}")
                self.__logger(error)

                self.__socket.close()
                self.__is_connected = False
                raise ReconnectError from error

            # Check that remote host responded correctly
            if received_message == WELCOME_MESSAGE:
                self.__logger("[TCP] Connected!")

                self.__is_connected = True
                # self.__socket.settimeout(None)
            else:
                self.__logger(
                    "[TCP] Remote host didn't respond correctly, disconnecting."
                )
                self.__socket.close()
                self.__is_connected = False
                raise ReconnectError

    def __keep_alive(self) -> None:
        while self.__running:
            self.__logger("[TCP], Checking connection...")

            # Send connection check command
            try:
                conncheck_response: str = asyncio.run(
                    self.request(CONNECTION_CHECK_MESSAGE)
                )
                if conncheck_response != CONNECTION_CHECK_EXPECTED_RESPONSE:
                    try:
                        self.__reconnect()
                    except ReconnectError:
                        pass
            except NotConnected:
                try:
                    self.__reconnect()
                except ReconnectError:
                    pass

            # Wait for connection check interval or or notification from other thread
            with self.__keep_alive_cv:
                self.__keep_alive_cv.wait(timeout=self.__keep_alive_interval)

    async def request(self, request_msg: str) -> str:
        """Sends a request to the Lumize DMX Engine and retuns its response"""

        # Try to send message
        try:
            # First try
            with self.__socket_lock:
                self.__socket.sendall(bytes(request_msg, "utf-8"))
                response_msg: bytes = self.__socket.recv(64)
                return response_msg.decode("utf-8").strip()
        except socket.error:
            try:
                self.__reconnect()
                try:
                    # Second try after reconnect
                    with self.__socket_lock:
                        self.__socket.sendall(bytes(request_msg, "utf-8"))
                        response_msg: bytes = self.__socket.recv(64)
                        return response_msg.decode("utf-8").strip()
                except socket.error as error:
                    raise NotConnected from error
            except ReconnectError as error:
                raise NotConnected from error

# Check if module is being run as program
if __name__ == "__main__":
    print("This is a module and it should not be run as program.")


import pandas as pd
import quandl, math
import numpy as np
from sklearn import preprocessing, cross_validation, svm
from sklearn.linear_model import LinearRegression

# get Google stock data set
df = quandl.get('WIKI/GOOGL')

df = df[['Adj. Open', 'Adj. High', 'Adj. Low', 'Adj. Close', 'Adj. Volume',]]
df['HL_PCT'] = (df['Adj. High'] - df['Adj. Close']) / df['Adj. Close'] * 100
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100

df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]

forecast_col = 'Adj. Close'
# Because ML can not work with na data
df.fillna(-99999, inplace=True)
# math.ceil(x) = smallest integer value greater than or equal to x.
# We are try to predict out 10 percent of the dataframe and you'll see that actually
# when will go out and do this.
# number of predict
forecast_out = int(math.ceil(0.01*len(df)))
print (forecast_out)
df['label'] = df[forecast_col].shift(-forecast_out)
# print (df['label'])
# print (df[forecast_col])
# delect the the column which value is NA
df.dropna(inplace=True)
# print (df['label'])

# print (df.head())

X = np.array(df.drop(['label'], 1))
y = np.array(df['label'])
# scale data to "Gaussian with zero mean and unit variance"
X = preprocessing.scale(X)

# 20% of data we want to actually use as testing data.
# Generate the training and test data
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)
# classifier
clf = LinearRegression(n_jobs=-1)
# clf = svm.SVR()
# clf = svm.SVR(kernel='poly')
clf.fit(X_train, y_train)
accuracy = clf.score(X_test, y_test)
print (accuracy)


class Solution:
    def XXX(self, nums: List[int]) -> List[List[int]]:
        def dfs(nums, num, path):
            path.append(num)

            # end case of dfs
            if len(path) == size:
                res.append(path)
            else:
                remains = nums[:]
                remains.remove(num)

                # further dfs
                for num in remains:
                    dfs(remains, num, path[:])

        res = []
        size = len(nums)
        for num in nums:
            path = []
            dfs(nums, num, path)

        return res


import scraper

def get_stats(usernames, game_mode=None):
    result = None
    if game_mode is None:
        result = Bedwars(usernames)
    elif game_mode == 'eight_one':
        result = SoloBedwars(usernames)
    elif game_mode == 'eight_two':
        result = DoublesBedwars(usernames)
    elif game_mode == 'four_three':
        result = ThreesBedwars(usernames)
    elif game_mode == 'four_four':
        result = FourFourBedwars(usernames)
    elif game_mode == 'two_four':
        result = TwoFourBedwars(usernames)
    else:
        result = Bedwars(usernames)

    return result.get_table()

class Bedwars:
    rows = ['^Solo.Wins$ #Solo Wins', '^Doubles.Wins$ #Doubles Wins',
            '^3v3v3v3.Wins$ #3v3v3v3 Wins', '^4v4v4v4.Wins$ #4v4v4v4 Wins',
            '^4v4.Wins$ #4v4 Wins', '^Overall.Wins$ #Total Wins',
            '^Overall.Wins$ / (^Overall.Wins$ + ^Overall.Losses$) #Win Rate',
            '^Overall.Kills$ #Kills', '^Overall.K/D$ #K/D',
            '^Overall.Final Kills$ #Final Kills', '^Overall.Final K/D$ #Final K/D',
            '^Overall.Kills$ + ^Overall.Final Kills$ #Total Kills']

    def __init__(self, usernames):
        self.usernames = usernames

    def get_table(self):
        usernames = self.usernames
        pages = scraper.get_player_pages(usernames)
        datasets = list(zip(usernames, [scraper.get_bw_data(page) for page in pages]))

        return scraper.make_bw_table(self.rows, datasets)

class SoloBedwars(Bedwars):
    rows = ['^Solo.Wins$ #Solo Wins',
            '^Solo.Wins$ / (^Solo.Wins$ + ^Solo.Losses$) #Win Rate',
            '^Solo.Kills$ #Kills', '^Solo.K/D$ #K/D',
            '^Solo.Final Kills$ #Final Kills', '^Solo.Final K/D$ #Final K/D',
            '^Solo.Kills$ + ^Solo.Final Kills$ #Total Kills']

class DoublesBedwars(Bedwars):
    rows = ['^Doubles.Wins$ #Doubles Wins',
            '^Doubles.Wins$ / (^Doubles.Wins$ + ^Doubles.Losses$) #Win Rate',
            '^Doubles.Kills$ #Kills', '^Doubles.K/D$ #K/D',
            '^Doubles.Final Kills$ #Final Kills', '^Doubles.Final K/D$ #Final K/D',
            '^Doubles.Kills$ + ^Doubles.Final Kills$ #Total Kills']

class ThreesBedwars(Bedwars):
    rows = ['^3v3v3v3.Wins$ #3v3v3v3 Wins',
            '^3v3v3v3.Wins$ / (^3v3v3v3.Wins$ + ^3v3v3v3.Losses$) #Win Rate',
            '^3v3v3v3.Kills$ #Kills', '^3v3v3v3.K/D$ #K/D',
            '^3v3v3v3.Final Kills$ #Final Kills', '^3v3v3v3.Final K/D$ #Final K/D',
            '^3v3v3v3.Kills$ + ^3v3v3v3.Final Kills$ #Total Kills']

class FourFourBedwars(Bedwars):
    rows = ['^4v4v4v4.Wins$ #4v4v4v4 Wins',
            '^4v4v4v4.Wins$ / (^4v4v4v4.Wins$ + ^4v4v4v4.Losses$) #Win Rate',
            '^4v4v4v4.Kills$ #Kills', '^4v4v4v4.K/D$ #K/D',
            '^4v4v4v4.Final Kills$ #Final Kills', '^4v4v4v4.Final K/D$ #Final K/D',
            '^4v4v4v4.Kills$ + ^4v4v4v4.Final Kills$ #Total Kills']

class TwoFourBedwars(Bedwars):
    rows = ['^4v4.Wins$ #4v4 Wins',
            '^4v4.Wins$ / (^4v4.Wins$ + ^4v4.Losses$) #Win Rate',
            '^4v4.Kills$ #Kills', '^4v4.K/D$ #K/D',
            '^4v4.Final Kills$ #Final Kills', '^4v4.Final K/D$ #Final K/D',
            '^4v4.Kills$ + ^4v4.Final Kills$ #Total Kills']

if __name__ == '__main__':
    # paco = TwoFourBedwars(['parcerx', 'ronansfire'])
    # print(paco.get_table())
    print(get_stats(['parcerx'], game_mode='eight_one'))


import tkinter as tk
from os import walk

# This function displays the clubs using a second window
def display_clubs(clubs):
    window = tk.Toplevel(root)
    window.title("Full Club Points")
    window.iconbitmap("icon.ico")

    #Turn dict into list
    results = [ [k,v] for k, v in clubs.items() ]

    #order list
    results.sort(key = lambda x: x[1])
    #print(results)
    #Display list
    results_listbox = tk.Listbox(window, width = 50, height = 50, font = ("Arial", ), bg=BG_COLOUR)

    #Adds each waka tot he Listbox "results_listbox"
    for x in results:

        if(x[[0][0]] == ""):
            continue

        current_waka = "{}".format(x)
        results_listbox.insert(0, current_waka)

    results_listbox.grid(row = 0, column = 0)
    #print(results)

# This function calculats the points for the teams from 1st to last
def points(current_year, final_races):
    clubs = {}
    # This code shows the years for the code
    for race in final_races:
        current_race = open("{}/{}".format(current_year, race),"r")

        for club in current_race:
            waka = club.strip().split(",")

            # The code below shows the points
            points = 0

            if(waka[0] == "1"):
                points = 8
            elif(waka[0] == "2"):
                points = 7
            elif(waka[0] == "3"):
                points = 6
            elif(waka[0] == "4"):
                points = 5
            elif(waka[0] == "5"):
                points = 4
            elif(waka[0] == "6"):
                points = 3
            elif(waka[0] == "7"):
                points = 2
            else:
                points = 1

            if(waka[5] not in clubs):
                clubs[waka[5]] = points
            else:
                clubs[waka[5]] = clubs.get(waka[5]) + points

        current_race.close()
    #print(clubs)

    display_clubs(clubs)

# This function displays the 2017 and 2018 folders to choose from.
def display_files():
    races = []
    current_years = years_chosen.get()

    for root, dirs, files in walk("{}".format(current_years)):
        races.extend(files)
        break
    #print(races)

    final_races = []

    for race in races:
        if("Final" in race):
            final_races.append(race)
    #print(final_races)
    points(current_years, final_races)

years = []

for root, dirs, files in walk("."):
    years.extend(dirs)
    break

# years = ["Wakanats 2017", "Wakanats 2018"]

BG_COLOUR = "PINK"
FG_COLOUR = "BLACK"
root = tk.Tk()

#this code sets the color of my background
root.configure(background = BG_COLOUR)

#this code give me the window title
root.title("Leaderboard")

#this code places my photo of my boat
root.wm_iconbitmap("icon.ico")

#this code shows the title
title = tk.Label(root, text = "Waka Ama\nCompetition",font = ("Arial", 20),bg = BG_COLOUR, fg = FG_COLOUR)
title.grid(row = 0, column = 0)

message = tk.Label(root, text = "At the beginning of each year Nga Kaihoe o Aotearoa, Waka Ama New Zealand hold their annual Sprint Nationals.\n There is a mixture of events at the competition in which regionalassociations compete for medals as well as for the overall association\n of the competition.",font = ("Arial", 12),bg = BG_COLOUR, fg = FG_COLOUR)
message.grid(row = 1, column = 0)

years_chosen = tk.StringVar()
years_chosen.set("Select a year:")

years_options = tk.OptionMenu(root, years_chosen, *years)
years_options.grid(row = 2, column = 0)

button = tk.Button(root, text = "Display files", command = display_files,font = ("Arial", "12"), bg = BG_COLOUR)
button.grid(row = 3, column = 0)

root.mainloop()


#!/usr/bin/env python

"""
Development utility to replay an ALS session based on a log file containing
the ALS.IN and ALS.OUT traces, and output it as protocol strings.

Usage: replay.py --log-file <path_to_log_file> --output-file <output_file>
"""

import argparse
from json_transformations import python_to_protocol_string, traces_to_test

argParser = argparse.ArgumentParser()
argParser.add_argument(
    "-l",
    "--log-file",
    help="Path to the log file containing ALS.IN and ALS.OUT traces.",
    required=True,
)
argParser.add_argument(
    "-o",
    "--output-file",
    help="Path to the output file containing all the ALS requests retrieved "
    + "from the log file. Then you can replay a session like this: "
    + "ada_language_server < <output_file>",
    required=False,
)
args = argParser.parse_args()

inout_file = args.log_file
output_file = args.output_file
test = traces_to_test(inout_file, None, True)
result = ""
for x in test:
    if "send" in x:
        result += python_to_protocol_string([x["send"]["request"]])

# Print on stdout if no output file has been specified
if output_file:
    with open(output_file, "w") as file:
        file.write(result + "\r")
else:
    print(result + "\r")


#!/usr/bin/env python
import argparse
import yaml

from paperwaster import publish_image_code, publish_message

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('--config', '-c', help='path to config file', default='config.yaml')
    ap.add_argument('--message', '-m', help='message to print')
    ap.add_argument('--font', '-f', help='name of the font to use', default='hack')
    ap.add_argument('--size', '-s', help='size of font', default=24, type=int)
    ap.add_argument('--image-code', '-ic', help='image code to print')
    ap.add_argument('--image', '-i', help='image code to print')
    args = ap.parse_args()
    config = yaml.safe_load(open(args.config))
    if args.message:
        publish_message(args.message, args.font, args.size, redis_uri=config['redis_uri'])

    if args.image_code:
        publish_image_code(args.image_code, redis_uri=config['redis_uri'])

    if args.image:
        ic = config.get('images', {}).get(args.image)
        if ic:
            publish_image_code(ic, redis_uri=config['redis_uri'])
        else:
            print('No image code for {}'.format(args.image))

if __name__ == '__main__':
    main()


import random

import hlt
from hlt import EAST, NORTH, SOUTH, STILL, WEST, Move, Square

myID, game_map = hlt.get_init()
hlt.send_init("MyPythonBot")

while True:
    game_map.get_frame()
    moves = [
        Move(square, random.choice((NORTH, EAST, SOUTH, WEST, STILL)))
        for square in game_map
        if square.owner == myID
    ]
    hlt.send_frame(moves)


"""netcat server."""
import argparse
import fcntl
import os
import select
import socket
import sys

from six.moves import queue

message_queues = queue.Queue()

def server_listen(port):
    """Listen and accept a connection."""
    global server, conn
    addr = (socket.gethostbyname(socket.gethostname()), port)
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(addr)
    server.listen(1)
    conn, addr = server.accept()
    conn.setblocking(False)

def set_nonblocking(fd):
    """Set fd non-blocking."""
    flag = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)

def main_loop(port):
    """Main message loop."""
    global conn
    server_listen(port)
    inputs = [conn, sys.stdin]
    outputs = []
    while inputs:
        set_nonblocking(sys.stdin.fileno())
        set_nonblocking(sys.stdout.fileno())
        readable, writable, exceptional = select.select(inputs, outputs, [])
        if not outputs:
            outputs = [conn] if sys.stdin in readable else [sys.stdout]
        for r in readable:
            msg = os.read(r.fileno(), 4096)
            if msg:
                message_queues.put(msg)
            else:
                sys.exit(0)
        for w in writable:
            try:
                msg = message_queues.get_nowait()
            except queue.Empty:
                pass
            else:
                os.write(w.fileno(), msg)
        for e in exceptional:
            try:
                inputs.remove(e)
                outputs.remove(e)
            except ValueError:
                pass

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Python netcat-like utility server"
        )
    parser.add_argument("-l", "--listen", nargs=1, help="listen on port.")
    args = parser.parse_args()
    main_loop(int(args.listen[0]))


from UnconventionalLiving.Tax import CanadaTax
from UnconventionalLiving.Savings import Savings

if __name__ == "__main__":

    canada_tax = CanadaTax()
    income = input("Annual Income: ")
    province = input("Province: ")
    after_tax = canada_tax.after_tax_income(income, province)
    # print (after_tax)
    age = input("Your age: ")
    in_TFSA = input("Amount currently in your TFSA: ")
    annual_budget = input("Desired annual Budget: ")
    savings = Savings(income, age, province, annual_budget, in_TFSA)
    # print(savings.TFSA_eligible)

FinancialCalculators/Suggested Annual Savings Locations (Canada)/UnconventionalLiving/__init__.py


import requests

# Define the API URL
api_url = "http://hn.algolia.com/api/v1/search_by_date?tags=story"

try:
    # Send a GET request to the API
    response = requests.get(api_url)

    # Check if the request was successful (status code 200)
    if response.status_code == 200:
        # Parse the JSON response
        data = response.json()

        # Get the latest story (assuming the data is sorted by date)
        latest_story = data['hits'][0]

        # Print the title and URL of the latest story
        print("Latest Story:")
        print("Title:", latest_story['title'])
        print("URL:", latest_story['url'])
    else:
        print("Error: Unable to fetch data from the API")
except Exception as e:
    print("Error:", str(e))


import os
import sys

def make_windows_friendly(string):
    chars_to_replace = ["<", ">", ":", "\"", "/", "\\", "|", "?", "*"]
    for char in chars_to_replace:
        string = string.replace(char, "#")
    return string

def create_folder(folder_name, dir_path):
    new_folder = os.path.join(dir_path[0:len(dir_path)-4] +
                              "/downloaded_songs/" + folder_name)
    try:
        os.mkdir(new_folder)
    except FileExistsError:
        pass

def create_downloaded_songs_folder(dir_path):
    if not os.path.isdir(dir_path[0:len(dir_path)-4] + "/downloaded_songs"):
        downloaded_songs_folder = os.path.join(dir_path[0:len(dir_path)-4] + "/downloaded_songs")
        os.mkdir(downloaded_songs_folder)

def check_all_packages():
    try:
        import flask
        import requests
        import googleapiclient
        import yt_dlp
    except:
        print("You don't have all packages, please download them with Package-download.bat")
        print("Press enter to leave application")
        input()
        sys.exit()

# Edulint done
# MyPy