"""
Python implementation of Token Passing algorithms to solve MAPD problems with delays
author: Giacomo Lodigiani (@Lodz97)
"""
from math import fabs
import random
from Simulation.CBS.cbs import CBS, Environment
from Simulation.markov_chains import MarkovChainsMaker
from collections import defaultdict

class TokenPassingRecovery(object):
    def __init__(self, agents, dimesions, obstacles, non_task_endpoints, simulation, a_star_max_iter=4000, k=0,
                 replan_every_k_delays=False, pd=None, p_max=1, p_iter=1, new_recovery=False):
        self.agents = agents
        self.dimensions = dimesions
        self.obstacles = set(obstacles)
        self.non_task_endpoints = non_task_endpoints
        if len(agents) > len(non_task_endpoints):
            print('There are more agents than non task endpoints, instance is not well-formed.')
            exit(1)
        # TODO: Check all properties for well-formedness
        self.token = {}
        self.simulation = simulation
        self.a_star_max_iter = a_star_max_iter
        self.k = k
        self.p_max = p_max
        if self.k != 0 and self.p_max != 1:
            print('Use of k and p robustness at same time not allowed.')
            exit(-1)
        if self.k < 0:
            print('k should be >= 0.')
            exit(1)
        if self.k == 0 and not new_recovery:
            print('k = 0 not supported for this recovery type.')
            exit(1)
        self.replan_every_k_delays = replan_every_k_delays
        if k == 0 and replan_every_k_delays:
            print('If k = 0 replan_every_k_delays must be False. Setting to False...')
            self.replan_every_k_delays = False
        if self.k == 0:
            if (self.p_max < 0 or self.p_max > 1):
                print('Max conflict probability must be between 0 and 1.')
                exit(1)
            self.pd = pd
            if self.p_max != 1 and not self.pd:
                print('To use p robustness need to set pd.')
                exit(1)
            if self.pd and (pd < 0 or pd > 1):
                print('Probability of delay must be between 0 and 1.')
                exit(1)
            self.p_iter = p_iter
            if self.p_iter <= 0:
                print('p_iter should be > 0.')
                exit(1)
        else:
            self.p_max = 1
            self.pd = None
            self.p_iter = 1
        self.new_recovery = new_recovery
        self.init_token()

    def init_token(self):
        self.token['agents'] = {}
        self.token['tasks'] = {}
        self.token['start_tasks_times'] = {}
        self.token['completed_tasks_times'] = {}
        for t in self.simulation.get_new_tasks():
            self.token['tasks'][t['task_name']] = [t['start'], t['goal']]
            self.token['start_tasks_times'][t['task_name']] = self.simulation.get_time()
        self.token['agents_to_tasks'] = {}
        self.token['completed_tasks'] = 0
        self.token['n_replans'] = 0
        self.token['path_ends'] = set()
        self.token['occupied_non_task_endpoints'] = set()
        self.token['delayed_agents'] = []
        self.token['delayed_agents_to_reach_task_start'] = []
        self.token['agent_at_end_path'] = []
        self.token['agent_at_end_path_pos'] = []
        self.token['agents_in_recovery_trial'] = []
        for a in self.agents:
            self.token['agents'][a['name']] = [a['start']]
            self.token['path_ends'].add(tuple(a['start']))
        self.token['prob_exceeded'] = False
        self.token['deadlock_count_per_agent'] = defaultdict(lambda: 0)

    def get_idle_agents(self):
        agents = {}
        for name, path in self.token['agents'].items():
            if len(path) == 1:
                agents[name] = path
        return agents

    def admissible_heuristic(self, task_pos, agent_pos):
        return fabs(task_pos[0] - agent_pos[0]) + fabs(task_pos[1] - agent_pos[1])

    def get_closest_task_name(self, available_tasks, agent_pos):
        closest = random.choice(list(available_tasks.keys()))
        dist = self.admissible_heuristic(available_tasks[closest][0], agent_pos)
        for task_name, task in available_tasks.items():
            if self.admissible_heuristic(task[0], agent_pos) < dist:
                closest = task_name
        return closest

    def get_moving_obstacles_agents(self, agents, time_start):
        obstacles = {}
        for name, path in agents.items():
            if len(path) > time_start and len(path) > 1:
                for i in range(time_start, len(path)):
                    k = i - time_start
                    obstacles[(path[i][0], path[i][1], k)] = name
                    for j in range(1, self.k + 1):
                        if i - j >= time_start:
                            obstacles[(path[i][0], path[i][1], k - j)] = name
                        obstacles[(path[i][0], path[i][1], k + j)] = name
                    # Mark last element with negative time to later turn it into idle obstacle
                    if i == len(path) - 1:
                        obstacles[(path[i][0], path[i][1], -k)] = name
        return obstacles

    def get_idle_obstacles_agents(self, agents_paths, delayed_agents, time_start):
        obstacles = set()
        for path in agents_paths:
            if len(path) == 1:
                obstacles.add((path[0][0], path[0][1]))
            if 1 < len(path) <= time_start:
                obstacles.add((path[-1][0], path[-1][1]))
        for agent_name in delayed_agents:
            obstacles.add(tuple(self.token['agents'][agent_name][0]))
        return obstacles

    def check_safe_idle(self, agent_pos):
        for task_name, task in self.token['tasks'].items():
            if tuple(task[0]) == tuple(agent_pos) or tuple(task[1]) == tuple(agent_pos):
                return False
        for start_goal in self.get_agents_to_tasks_starts_goals():
            if tuple(start_goal) == tuple(agent_pos):
                return False
        return True

    def get_closest_non_task_endpoint(self, agent_pos):
        dist = -1
        res = -1
        for endpoint in self.non_task_endpoints:
            if endpoint not in self.token['occupied_non_task_endpoints']:
                if dist == -1:
                    dist = self.admissible_heuristic(endpoint, agent_pos)
                    res = endpoint
                else:
                    tmp = self.admissible_heuristic(endpoint, agent_pos)
                    if tmp < dist:
                        dist = tmp
                        res = endpoint
        if res == -1:
            print('Error in finding non-task endpoint, is instance well-formed?')
            exit(1)
        return res

    def update_ends(self, agent_pos):
        if tuple(agent_pos) in self.token['path_ends']:
            self.token['path_ends'].remove(tuple(agent_pos))
        elif tuple(agent_pos) in self.token['occupied_non_task_endpoints']:
            self.token['occupied_non_task_endpoints'].remove(tuple(agent_pos))

    def get_agents_to_tasks_goals(self):
        goals = set()
        for el in self.token['agents_to_tasks'].values():
            goals.add(tuple(el['goal']))
        return goals

    def get_agents_to_tasks_starts_goals(self):
        starts_goals = set()
        for el in self.token['agents_to_tasks'].values():
            starts_goals.add(tuple(el['goal']))
            starts_goals.add(tuple(el['start']))
        return starts_goals

    def get_completed_tasks(self):
        return self.token['completed_tasks']

    def get_completed_tasks_times(self):
        return self.token['completed_tasks_times']

    def get_n_replans(self):
        return self.token['n_replans']

    def get_token(self):
        return self.token

    def get_k(self):
        return self.k

    def get_replan_every_k_delays(self):
        return self.replan_every_k_delays

    def search(self, cbs, agent_name, moving_obstacles_agents):
        path = None
        if self.p_max == 1:
            path = cbs.search()
        else:
            self.token['prob_exceeded'] = False
            mk = MarkovChainsMaker(self.token['agents'], self.pd)
            for iter in range(self.p_iter):
                path = cbs.search()
                tmp = []
                if path and len(path[agent_name]) > 1:
                    for el in path[agent_name]:
                        tmp.append([el['x'], el['y']])
                    dic = mk.get_conflict_prob_given_path(tmp)
                    if dic['prob'] > self.p_max:
                        self.token['prob_exceeded'] = True
                        print('Conflict probablility to high (', dic['prob'], ') replanning...')
                        path = None
                        moving_obstacles_agents[(dic['pos_max_conf'][0], dic['pos_max_conf'][1], -1)] = agent_name
                    else:
                        break
        return path

    def go_to_closest_non_task_endpoint(self, agent_name, agent_pos, all_idle_agents, all_delayed_agents):
        closest_non_task_endpoint = self.get_closest_non_task_endpoint(agent_pos)
        moving_obstacles_agents = self.get_moving_obstacles_agents(self.token['agents'], 0)
        idle_obstacles_agents = self.get_idle_obstacles_agents(all_idle_agents.values(), all_delayed_agents, 0)
        agent = {'name': agent_name, 'start': agent_pos, 'goal': closest_non_task_endpoint}
        env = Environment(self.dimensions, [agent], self.obstacles | idle_obstacles_agents, moving_obstacles_agents,
                          a_star_max_iter=self.a_star_max_iter)
        cbs = CBS(env)
        path_to_non_task_endpoint = self.search(cbs, agent_name, moving_obstacles_agents)
        if not path_to_non_task_endpoint:
            print("Solution to non-task endpoint not found for agent", agent_name, " instance is not well-formed.")
            self.deadlock_recovery(agent_name, agent_pos, all_idle_agents, all_delayed_agents, 4)
            # exit(1)
        else:
            print('No available task for agent', agent_name, ' moving to safe idling position...')
            self.update_ends(agent_pos)
            self.token['occupied_non_task_endpoints'].add(tuple(closest_non_task_endpoint))
            self.token['agents_to_tasks'][agent_name] = {'task_name': 'safe_idle', 'start': agent_pos,
                                                         'goal': closest_non_task_endpoint, 'predicted_cost': 0}
            self.token['agents'][agent_name] = []
            for el in path_to_non_task_endpoint[agent_name]:
                self.token['agents'][agent_name].append([el['x'], el['y']])

    def get_random_close_cell(self, agent_pos, r):
        while True:
            cell = (agent_pos[0] + random.choice(range(-r - 1, r + 1)), agent_pos[1] + random.choice(range(-r - 1, r + 1)))
            if cell not in self.obstacles and cell not in self.token['path_ends'] and \
                    cell not in self.token['occupied_non_task_endpoints'] \
                    and cell not in self.get_agents_to_tasks_goals() \
                    and 0 <= cell[0] < self.dimensions[0] and 0 <= cell[1] < self.dimensions[1]:
                return cell

    def deadlock_recovery(self, agent_name, agent_pos, all_idle_agents, all_delayed_agents, r):
        self.token['deadlock_count_per_agent'][agent_name] += 1
        if self.token['deadlock_count_per_agent'][agent_name] >= 5:
            self.token['deadlock_count_per_agent'][agent_name] = 0
            random_close_cell = self.get_random_close_cell(agent_pos, r)
            moving_obstacles_agents = self.get_moving_obstacles_agents(self.token['agents'], 0)
            idle_obstacles_agents = self.get_idle_obstacles_agents(all_idle_agents.values(), all_delayed_agents, 0)
            agent = {'name': agent_name, 'start': agent_pos, 'goal': random_close_cell}
            env = Environment(self.dimensions, [agent], self.obstacles | idle_obstacles_agents, moving_obstacles_agents,
                              a_star_max_iter=self.a_star_max_iter)
            cbs = CBS(env)
            path_to_non_task_endpoint = self.search(cbs, agent_name, moving_obstacles_agents)
            if not path_to_non_task_endpoint:
                print("No solution to deadlock recovery for agent", agent_name, " retrying later.")
            else:
                # Don't consider this a task, so don't add to agents_to_tasks
                print('Agent', agent_name, 'causing deadlock, moving to safer position...')
                self.update_ends(agent_pos)
                self.token['agents'][agent_name] = []
                for el in path_to_non_task_endpoint[agent_name]:
                    self.token['agents'][agent_name].append([el['x'], el['y']])

    def time_forward(self):
        # Update completed tasks
        for agent_name in self.token['agents']:
            pos = self.simulation.actual_paths[agent_name][-1]
            if agent_name in self.token['agents_to_tasks'] and (pos['x'], pos['y']) == tuple(
                    self.token['agents_to_tasks'][agent_name]['goal']) \
                    and len(self.token['agents'][agent_name]) == 1 and self.token['agents_to_tasks'][agent_name][
                'task_name'] != 'safe_idle':
                self.token['completed_tasks'] = self.token['completed_tasks'] + 1
                self.token['completed_tasks_times'][
                    self.token['agents_to_tasks'][agent_name]['task_name']] = self.simulation.get_time()
                self.token['agents_to_tasks'].pop(agent_name)
            if agent_name in self.token['agents_to_tasks'] and (pos['x'], pos['y']) == tuple(
                    self.token['agents_to_tasks'][agent_name]['goal']) \
                    and len(self.token['agents'][agent_name]) == 1 and self.token['agents_to_tasks'][agent_name][
                'task_name'] == 'safe_idle':
                self.token['agents_to_tasks'].pop(agent_name)

        # Check delayed agents and agents affected by delays
        if self.new_recovery:
            self.token['delayed_agents'] = self.simulation.get_delayed_agents()
            for name in self.token['delayed_agents']:
                print('Agent', name, 'delayed or affected by delay!')
                path = self.token['agents'][name]
                self.token['n_replans'] = self.token['n_replans'] + 1
                self.update_ends(path[-1])
                if path[0] in self.non_task_endpoints:
                    self.token['occupied_non_task_endpoints'].add(tuple(path[0]))
                else:
                    self.token['path_ends'].add(tuple(path[0]))
                if name in self.token['agents_to_tasks']:
                    if self.token['agents_to_tasks'][name]['start'] not in path:
                        self.token['delayed_agents_to_reach_task_start'].append(name)
                self.token['agents'][name] = [path[0]]
        else:
            self.token['delayed_agents'] = []
            delayed_agents_pos = []
            for name, path in self.token['agents'].items():
                actual_state = self.simulation.get_actual_paths()[name][-1]
                if path[0] != [actual_state['x'], actual_state['y']]:
                    print('Agent', name, 'delayed!')
                    # self.token['n_replans'] = self.token['n_replans'] + 1
                    self.token['delayed_agents'].append(name)
                    delayed_agents_pos.append([actual_state['x'], actual_state['y']])
                    self.update_ends(path[-1])
                    pos = tuple([actual_state['x'], actual_state['y']])
                    if pos in self.non_task_endpoints:
                        self.token['occupied_non_task_endpoints'].add(pos)
                    else:
                        self.token['path_ends'].add(pos)
                    if self.token['agents_to_tasks'][name]['start'] not in path:
                        self.token['delayed_agents_to_reach_task_start'].append(name)
                    self.token['agents'][name] = [[actual_state['x'], actual_state['y']]]
            for name, path in self.token['agents'].items():
                if name not in self.token['delayed_agents']:
                    for i in range(len(path)):
                        if path[i] in delayed_agents_pos:
                            print('Agent', name, 'affected by delay!')
                            self.token['n_replans'] = self.token['n_replans'] + 1
                            self.update_ends(path[-1])
                            if path[0] in self.non_task_endpoints:
                                self.token['occupied_non_task_endpoints'].add(tuple(path[0]))
                            else:
                                self.token['path_ends'].add(tuple(path[0]))
                            if self.token['agents_to_tasks'][name]['start'] not in path:
                                self.token['delayed_agents_to_reach_task_start'].append(name)
                            self.token['agents'][name] = [path[0]]
                            break

        # TODO do this maybe only for old recovery
        # Check if somehow an agent path collides with an idle agent (may happen because of delays)
        if not self.new_recovery:
            for name, path in self.get_idle_agents().items():
                self.token['agent_at_end_path'].append(name)
                self.token['agent_at_end_path_pos'].append(path[0])
            for name, path in self.token['agents'].items():
                if name not in self.token['agent_at_end_path']:
                    for i in range(len(path)):
                        if path[i] in self.token['agent_at_end_path_pos']:
                            print('Agent', name, 'will impact end task agent, replanning...')
                            # self.update_ends(path[-1])
                            if path[0] in self.non_task_endpoints:
                                self.token['occupied_non_task_endpoints'].add(tuple(path[0]))
                            else:
                                self.token['path_ends'].add(tuple(path[0]))
                            # TODO check this rare keyerror
                            if self.token['agents_to_tasks'][name]['start'] not in path:
                                self.token['delayed_agents_to_reach_task_start'].append(name)
                            self.token['agents'][name] = [path[0]]
                            break
            self.token['agent_at_end_path'] = []
            self.token['agent_at_end_path_pos'] = []

        # Collect new tasks and assign them, if possible
        for t in self.simulation.get_new_tasks():
            self.token['tasks'][t['task_name']] = [t['start'], t['goal']]
            self.token['start_tasks_times'][t['task_name']] = self.simulation.get_time()
        idle_agents = self.get_idle_agents()
        while len(idle_agents) > 0:
            agent_name = random.choice(list(idle_agents.keys()))
            # agent_name = list(idle_agents.keys())[0]
            all_idle_agents = self.token['agents'].copy()
            all_idle_agents.pop(agent_name)
            all_delayed_agents = self.token['delayed_agents'].copy()
            if agent_name in all_delayed_agents:
                all_delayed_agents.remove(agent_name)
            agent_pos = idle_agents.pop(agent_name)[0]
            available_tasks = {}
            for task_name, task in self.token['tasks'].items():
                if tuple(task[0]) not in self.token['path_ends'].difference({tuple(agent_pos)}) and tuple(
                        task[1]) not in self.token['path_ends'].difference({tuple(agent_pos)}) \
                        and tuple(task[0]) not in self.get_agents_to_tasks_goals() and tuple(
                    task[1]) not in self.get_agents_to_tasks_goals():
                    available_tasks[task_name] = task
            if len(available_tasks) > 0 or agent_name in self.token['agents_to_tasks']:
                if agent_name in self.token['agents_to_tasks']:
                    closest_task_name = self.token['agents_to_tasks'][agent_name]['task_name']
                    if agent_name in self.token['delayed_agents_to_reach_task_start']:
                        closest_task = [self.token['agents'][agent_name][0],
                                        self.token['agents_to_tasks'][agent_name]['goal']]
                    else:
                        closest_task = [self.token['agents_to_tasks'][agent_name]['start'],
                                        self.token['agents_to_tasks'][agent_name]['goal']]
                else:
                    closest_task_name = self.get_closest_task_name(available_tasks, agent_pos)
                    closest_task = available_tasks[closest_task_name]
                moving_obstacles_agents = self.get_moving_obstacles_agents(self.token['agents'], 0)
                idle_obstacles_agents = self.get_idle_obstacles_agents(all_idle_agents.values(), all_delayed_agents, 0)
                agent = {'name': agent_name, 'start': agent_pos, 'goal': closest_task[0]}
                env = Environment(self.dimensions, [agent], self.obstacles | idle_obstacles_agents,
                                  moving_obstacles_agents, a_star_max_iter=self.a_star_max_iter)
                cbs = CBS(env)
                path_to_task_start = self.search(cbs, agent_name, moving_obstacles_agents)
                if not path_to_task_start:
                    print("Solution not found to task start for agent", agent_name, " idling at current position...")
                    if len(self.token['delayed_agents']) == 0 and not self.token['prob_exceeded']:
                        print('Instance is not well-formed or a_star_max_iter is too low for this environment.')
                        self.deadlock_recovery(agent_name, agent_pos, all_idle_agents, all_delayed_agents, 4)
                        # exit(1)
                else:
                    print("Solution found to task start for agent", agent_name, " searching solution to task goal...")
                    cost1 = env.compute_solution_cost(path_to_task_start)
                    # Use cost - 1 because idle cost is 1
                    moving_obstacles_agents = self.get_moving_obstacles_agents(self.token['agents'], cost1 - 1)
                    idle_obstacles_agents = self.get_idle_obstacles_agents(all_idle_agents.values(), all_delayed_agents,
                                                                           cost1 - 1)
                    agent = {'name': agent_name, 'start': closest_task[0], 'goal': closest_task[1]}
                    env = Environment(self.dimensions, [agent], self.obstacles | idle_obstacles_agents,
                                      moving_obstacles_agents, a_star_max_iter=self.a_star_max_iter)
                    cbs = CBS(env)
                    path_to_task_goal = self.search(cbs, agent_name, moving_obstacles_agents)
                    if not path_to_task_goal:
                        print("Solution not found to task goal for agent", agent_name, " idling at current position...")
                        if len(self.token['delayed_agents']) == 0 and not self.token['prob_exceeded']:
                            print('Instance is not well-formed  or a_star_max_iter is too low for this environment.')
                            self.deadlock_recovery(agent_name, agent_pos, all_idle_agents, all_delayed_agents, 4)
                            # exit(1)
                    else:
                        print("Solution found to task goal for agent", agent_name, " doing task...")
                        cost2 = env.compute_solution_cost(path_to_task_goal)
                        if agent_name not in self.token['agents_to_tasks']:
                            self.token['tasks'].pop(closest_task_name)
                            task = available_tasks.pop(closest_task_name)
                        else:
                            task = closest_task
                        if agent_name in self.token['delayed_agents_to_reach_task_start']:
                            self.token['delayed_agents_to_reach_task_start'].remove(agent_name)
                        last_step = path_to_task_goal[agent_name][-1]
                        self.update_ends(agent_pos)
                        self.token['path_ends'].add(tuple([last_step['x'], last_step['y']]))
                        self.token['agents_to_tasks'][agent_name] = {'task_name': closest_task_name, 'start': task[0],
                                                                     'goal': task[1], 'predicted_cost': cost1 + cost2}
                        self.token['agents'][agent_name] = []
                        for el in path_to_task_start[agent_name]:
                            self.token['agents'][agent_name].append([el['x'], el['y']])
                        # Don't repeat twice same step
                        self.token['agents'][agent_name] = self.token['agents'][agent_name][:-1]
                        for el in path_to_task_goal[agent_name]:
                            self.token['agents'][agent_name].append([el['x'], el['y']])
            elif self.check_safe_idle(agent_pos):
                print('No available tasks for agent', agent_name, ' idling at current position...')
            else:
                self.go_to_closest_non_task_endpoint(agent_name, agent_pos, all_idle_agents, all_delayed_agents)

        # Advance along paths in the token
        if not self.new_recovery:
            for name, path in self.token['agents'].items():
                if len(path) > 1:
                    self.token['agents'][name] = path[1:]


import logging
import re

from crawler.config.centres import CENTRE_DATA_SOURCE_RABBITMQ, get_centres_config
from crawler.constants import (
    CENTRE_KEY_LAB_ID_DEFAULT,
    RABBITMQ_CREATE_FEEDBACK_ORIGIN_PLATE,
    RABBITMQ_CREATE_FEEDBACK_ORIGIN_SAMPLE,
)
from crawler.exceptions import TransientRabbitError
from crawler.helpers.sample_data_helpers import normalise_plate_coordinate
from crawler.rabbit.messages.parsers.create_plate_message import CreatePlateError, ErrorType

LOGGER = logging.getLogger(__name__)

class CreatePlateValidator:
    def __init__(self, message, config):
        self._message = message
        self._config = config

        self._centres = None

    def validate(self):
        LOGGER.debug("Starting validation of create message.")

        self._set_centre_conf()
        self._validate_plate()
        self._validate_samples()

        LOGGER.debug("Validation finished.")
        self._message.log_error_count()

    @property
    def centres(self):
        if self._centres is None:
            try:
                self._centres = get_centres_config(self._config, CENTRE_DATA_SOURCE_RABBITMQ)
            except Exception:
                raise TransientRabbitError("Unable to reach MongoDB while getting centres config.")

        return self._centres

    def _set_centre_conf(self):
        """Find a centre from the list of those we're accepting RabbitMQ messages for and store the config for it."""
        lab_id_field = self._message.lab_id
        try:
            self._message.centre_config = next(
                (c for c in self.centres if c[CENTRE_KEY_LAB_ID_DEFAULT] == lab_id_field.value)
            )
        except StopIteration:
            self._message.add_error(
                CreatePlateError(
                    type=ErrorType.ValidationCentreNotConfigured,
                    origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_PLATE,
                    description=(
                        f"The lab ID provided '{lab_id_field.value}' "
                        "is not configured to receive messages via RabbitMQ."
                    ),
                    field=lab_id_field.name,
                )
            )

    def _validate_plate(self):
        """Perform validation of the plate field in the message values for sanity.
        This does not check that the message can be inserted into the relevant databases.
        """
        # Ensure that the plate barcode isn't an empty string.
        plate_barcode_field = self._message.plate_barcode
        if not plate_barcode_field.value:
            self._message.add_error(
                CreatePlateError(
                    type=ErrorType.ValidationUnpopulatedField,
                    origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_PLATE,
                    description=f"Value for field '{plate_barcode_field.name}' has not been populated.",
                    field=plate_barcode_field.name,
                )
            )

    def _validate_samples(self):
        """Perform validation of the samples array in the message.
        This does not check that the message can be inserted into the relevant databases.
        """
        if self._message.total_samples == 0:
            return

        sample_uuid_field_name = self._message.samples.value[0].sample_uuid.name
        for sample_uuid in self._message.duplicated_sample_values[sample_uuid_field_name]:
            self._message.add_error(
                CreatePlateError(
                    type=ErrorType.ValidationNonUniqueValue,
                    origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_SAMPLE,
                    description=f"Sample UUID {sample_uuid} exists more than once in the message.",
                    sample_uuid=sample_uuid,
                    field=sample_uuid_field_name,
                )
            )

        self._message.validated_samples = 0
        for sample in self._message.samples.value:
            if self._validate_sample(sample):
                self._message.validated_samples += 1

    def _validate_sample_field_populated(self, field, sample_uuid):
        if not field.value:
            self._message.add_error(
                CreatePlateError(
                    type=ErrorType.ValidationUnpopulatedField,
                    origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_SAMPLE,
                    description=f"Value for field '{field.name}' on sample '{sample_uuid}' has not been populated.",
                    sample_uuid=sample_uuid,
                    field=field.name,
                )
            )

            return False

        return True

    def _validate_sample_field_unique(self, field, sample_uuid, normalise_func=None):
        normalised_value = field.value
        if normalise_func is not None:
            normalised_value = normalise_func(normalised_value)

        if normalised_value in self._message.duplicated_sample_values[field.name]:
            self._message.add_error(
                CreatePlateError(
                    type=ErrorType.ValidationNonUniqueValue,
                    origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_SAMPLE,
                    description=(
                        f"Field '{field.name}' on sample '{sample_uuid}' contains the value '{field.value}' "
                        "which is used in more than one sample but should be unique."
                    ),
                    sample_uuid=sample_uuid,
                    field=field.name,
                )
            )

            return False

        return True

    def _validate_sample_field_matches_regex(self, regex, field, sample_uuid):
        if not regex.match(field.value):
            self._message.add_error(
                CreatePlateError(
                    type=ErrorType.ValidationInvalidFormatValue,
                    origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_SAMPLE,
                    description=(
                        f"Field '{field.name}' on sample '{sample_uuid}' contains the value '{field.value}' "
                        "which doesn't match the expected format for values in this field."
                    ),
                    sample_uuid=sample_uuid,
                    field=field.name,
                )
            )

            return False

        return True

    def _validate_sample_field_no_later_than(self, timestamp, field, sample_uuid):
        if field.value > timestamp:
            self._message.add_error(
                CreatePlateError(
                    type=ErrorType.ValidationOutOfRangeValue,
                    origin=RABBITMQ_CREATE_FEEDBACK_ORIGIN_SAMPLE,
                    description=(
                        f"Field '{field.name}' on sample '{sample_uuid}' contains the value '{field.value}' "
                        f"which is too recent and should be lower than '{timestamp}'."
                    ),
                    sample_uuid=sample_uuid,
                    field=field.name,
                )
            )

            return False

        return True

    def _validate_sample(self, sample):
        """Perform validation of complete and consistent data for a single sample in the message."""
        valid = True

        # Ensure the sample UUID is unique
        sample_uuid_field = sample.sample_uuid
        sample_uuid = sample_uuid_field.value
        if sample_uuid in self._message.duplicated_sample_values[sample_uuid_field.name]:
            valid = False

        # Validate root sample ID
        root_sample_id_field = sample.root_sample_id
        if not self._validate_sample_field_populated(
            root_sample_id_field, sample_uuid
        ) or not self._validate_sample_field_unique(root_sample_id_field, sample_uuid):
            valid = False

        # Validate RNA ID
        rna_id_field = sample.rna_id
        if not self._validate_sample_field_populated(
            rna_id_field, sample_uuid
        ) or not self._validate_sample_field_unique(rna_id_field, sample_uuid):
            valid = False

        # Validate COG UK ID
        cog_uk_id_field = sample.cog_uk_id
        if not self._validate_sample_field_populated(
            cog_uk_id_field, sample_uuid
        ) or not self._validate_sample_field_unique(cog_uk_id_field, sample_uuid):
            valid = False

        # Validate plate coordinates
        plate_coordinate_field = sample.plate_coordinate
        if not self._validate_sample_field_matches_regex(
            re.compile(r"^[A-H](?:0?[1-9]|1[0-2])$"),  # A1 - H12 or A01 padded format
            plate_coordinate_field,
            sample_uuid,
        ) or not self._validate_sample_field_unique(plate_coordinate_field, sample_uuid, normalise_plate_coordinate):
            valid = False

        # Validate tested date is not newer than the message create date
        message_create_date = self._message.message_create_date.value
        tested_date_field = sample.tested_date
        if not self._validate_sample_field_no_later_than(message_create_date, tested_date_field, sample_uuid):
            valid = False

        return valid


from django.urls import path

from . import views
from .views import CategoryListAPIView, CategoryRetrieveAPIView, CategoryCreateAPIView, BookListAPIView,\
    BookDetailAPIView, BookCreateAPIView, ProductListAPIView, ProductRetrieveAPIView,ProductCreateAPIView, \
    ProductUpdateAPIView, CategoryUpdateAPIView, BookUpdateAPIView
from .views import *
urlpatterns = [
    path('category/list/', CategoryListAPIView.as_view(), name='category_list'),
    path('category/detail/<int:pk>/', CategoryRetrieveAPIView.as_view(), name='category_detail'),
    path('category/create/', CategoryCreateAPIView.as_view(), name='category_create'),
    path('category/update/<int:pk>/', CategoryUpdateAPIView.as_view(), name='category_update'),

    path('book/create/', BookCreateAPIView.as_view(), name='book_create'),
    path('book/list/', BookListAPIView.as_view(), name='book_list'),
    path('book/detail/<int:pk>/', BookDetailAPIView.as_view(), name='book_detail'),
    path('book/update/<int:pk>/', BookUpdateAPIView.as_view(), name='book_detail'),

    path('product/list/', ProductListAPIView.as_view(), name='product_list'),
    path('product/detail/<int:pk>/', ProductRetrieveAPIView.as_view(), name='product_detail'),
    path('product/create/', ProductCreateAPIView.as_view(), name='product_detail'),
    path('product/update/<int:pk>/', ProductUpdateAPIView.as_view(), name='product_detail'),

    path('show/data/', views.json_response, name='json_response'),
    path('show/data/2/', views.json_response2, name='json_response'),
]


import binascii
import re
import os
import csv
import shutil
import argparse
from utils import *
import numpy as np
import csv

############################ To get All  Video Trunck info #######################################################
# Read info from cmd, and create relative folder
parser = argparse.ArgumentParser()
parser.add_argument('--input_file', type=str)
parser.add_argument('--save_tape', action='store_true')
args = parser.parse_args()

input_file = args.input_file
input_dir = os.path.dirname(input_file)

output_name = input_file.split('/')[-1].split('.')[0]+'.meta'
output_dir = os.path.join(input_dir, input_file.split('/')[-1].split('.')[0] +  '_audio')
if os.path.isdir(output_dir):
    shutil.rmtree(output_dir)
os.mkdir(output_dir)
os.mkdir(os.path.join(output_dir, 'clips'))
os.mkdir(os.path.join(output_dir, 'other_streams'))

cut_cmd='ffmpeg -i {} -c copy -vn -loglevel quiet "{}/Audio.mp4"'.format(
    input_file, output_dir
)
exit_code = os.system(cut_cmd)
if exit_code != 0:
    print('command failed:', cut_cmd)

print('Succeed in generating audio')

Audio =  os.path.join(output_dir, 'Audio.mp4')
# record the All Frames info, including I, B,P frames ...
cut_cmd = 'FFREPORT=file={}:level=56 ffmpeg -i {}  -f -segment_frames -reset_timestamps 1 -loglevel quiet'.format(
    os.path.join(output_dir, 'allFramesInfo.log'), Audio
    )
exit_code = os.system(cut_cmd)
if exit_code == 0:
    print('Faild in getting Frames info')
print('Success in getting allFramesInfo.log')

allFramesInfoPath = os.path.join(output_dir, 'allFramesInfo.log')

# To get IDR info by reading the log file, that the corresponding IDR sample number, IDR byteoffset

audioSize = [] #[size]

with open(allFramesInfoPath, 'r') as file:
    lines = file.read().splitlines()
    for row in lines:
        if "AVIndex stream 0" in row:
            # print(row)
            audioSize.append(int(row.split(',')[9].split(' ', 2)[2]))
            #c = int(row.split(',')[6].split(' ', 2)[2])
            #audioSize.append([b, c])

file.close()
print(audioSize)
print("****** auido size  overall")
x = 0
for i in  audioSize:
    x+=i
print(x)

############################ Audio Grouping #######################################################
targetSize = 4500000  #4.5MB
overlap = 780         #大约五秒？
cutPlan = []
overall = []
sum = 0
start = 0
i = 0
while(i < len(audioSize)):
    overlap = 80000    #大约五秒？
    sum = sum + audioSize[i]
    if (sum >= targetSize):
        overall.append(sum)
        cutPlan.append([start, i+1])
        sum = 0
        minusOffset = 0
        while(overlap > 0):
            overlap = overlap - audioSize[i + minusOffset]
            minusOffset = minusOffset + 1
        start = i + 1 - minusOffset
        i = start - 1
        # print(start)
    i = i + 1

if(start != len(audioSize) - 1):
    cutPlan.append([start])
cutPlan[0] = [cutPlan[0][1]]
print('##### cut plan ######')
print(cutPlan)
#[[0, 5], [4, 9], [8, 13], [12, 17], [16, 18]]
i = 0
while i < len(cutPlan):
    string = ",".join(str(x) for x in cutPlan[i])
    cut_cmd='ffmpeg -i {} -f segment -segment_frames {} -reset_timestamps 1 -c copy -loglevel quiet "{}/{}clip_%d.mp4"'.format(
            Audio, string, os.path.join(output_dir, 'clips'), i
        )
    exit_code = os.system(cut_cmd)
    if exit_code != 0:
        print('command failed:', cut_cmd)

    # for the middle
    if (i == 0) :
        clip_path1 = "{}/{}clip_{}.mp4".format(os.path.join(output_dir, 'clips'), i, 1)
        cut_cmd_1 = 'rm -f {}'.format(clip_path1)
        exit_code = os.system(cut_cmd_1)
        if exit_code != 0:
            print('command failed:', cut_cmd_1)

    elif (i > 0  and i < len(cutPlan)-1 ):
        clip_path1 = "{}/{}clip_{}.mp4".format(os.path.join(output_dir, 'clips'), i, 0)
        clip_path2 = "{}/{}clip_{}.mp4".format(os.path.join(output_dir, 'clips'),i, 2)
        cut_cmd_1 = 'rm -f {}'.format(clip_path1)
        cut_cmd_2 = 'rm -f {}'.format(clip_path2)
        exit_code = os.system(cut_cmd_1)
        if exit_code != 0:
            print('command failed:', cut_cmd_1)
        exit_code = os.system(cut_cmd_2)
        if exit_code != 0:
            print('command failed:', cut_cmd_2)
    else:
        clip_path1 = "{}/{}clip_{}.mp4".format(os.path.join(output_dir, 'clips'),i, 0)
        cut_cmd_1 = 'rm -f {}'.format(clip_path1)
        exit_code = os.system(cut_cmd_1)
        if exit_code != 0:
            print('command failed:', cut_cmd_1)

    i += 1

print('Succeed in partition videos base on IDR')


import os
import sys
import time, calendar
import configparser
import logging
import logging.handlers
from datetime import datetime
import pandas as pd

from PyQt5.QAxContainer import *
from PyQt5.QtCore import *
from PyQt5.QtTest import *

from stocklab.kiwoom.config.errorCode import *
from stocklab.kiwoom.config.kiwoomType import *
from stocklab.kiwoom.config.slack import *
from stocklab.db_handler.firbaseRealDBHandler import FirebaseRealDBHandler

class Thread1(QThread):

    def __init__(self, parent, plogger):
        super().__init__(parent)
        self.parent = parent
        self.plogger = plogger
        self.threadCnt = 0

    def run(self):
        while True:
            account_list = self.parent.dynamicCall("GetLoginInfo(QString)", "ACCNO")  # 계좌번호 반환
            self.plogger.info("Count %s ::: account_list : %s" % (self.threadCnt, account_list))
            self.threadCnt += 1
            time.sleep(60)  # 10초마다 계좌정보요구. 접속끊어졌는지 체크

class sysTrading(QAxWidget):
    def __init__(self, parent, mode=None):
        super().__init__()
        ## 환경세팅 #######################################################################################
        self.parent = parent
        self.realType = RealType()
        global logger  # 전체에서 로그를 사용하기 위해 global로 선언을 해줌(전역 변수)
        logger = logging.getLogger('upperLimitPriceTradingLogger')  # 로그 인스턴스를 만든다
        self.set_logger()  # 로그 인스턴스 환경 설정을 셋팅함
        self.slack = MyMsg()  # 슬랙 동작
        self.slack.send_msg(msg="bsking1 슬랙메시지 전송하기")
        self.Fdb = FirebaseRealDBHandler()._client
        logger.debug("Kiwoom() class start.")
        ## config.ini #######################################################################################
        if mode not in ["DEMO_STRADE", "REAL_STRADE", "DEMO_FTRADE", "REAL_FTRADE"]:
            raise Exception("Need to run_mode(DEMO_STRADE or REAL_STRADE or DEMO_FTRADE or REAL_FTRADE)")
        run_mode = mode
        config = configparser.ConfigParser()
        config.read('conf/config.ini')
        self.account = config[run_mode]['account']
        self.use_money = int(config[run_mode]['use_money']) #실제 투자에 사용할 금액
        self.use_money_percent = float(config[run_mode]['use_money_percent']) # 현재 사용안함... 예수금에서 실제 사용할 비율
        self.use_money = int(self.use_money * self.use_money_percent)
        # logger.info("trading money: %s" % self.use_money)
        self.unit_money = int(self.use_money/100)  # 실제 투자에 사용할 금액
        self.maxStockNum = int(config[run_mode]['maxStockNum'])  # 실제 투자에 사용할 금액
        logger.debug("account(config.ini) : %s trading money: %s unit money: %s maxStockNum %s"
                     %(self.account,self.use_money,self.unit_money,self.maxStockNum))

        ######### 초기 셋팅 func들 바로 실행
        self.setControl("KHOPENAPI.KHOpenAPICtrl.1") # 레지스트리에 저장된 api 모듈 불러오기
        self.OnEventConnect.connect(self.login_slot)  # 로그인 관련 이벤트
        self.OnReceiveTrData.connect(self.trdata_slot)  # 트랜잭션 요청 관련 이벤트
        self.OnReceiveMsg.connect(self.msg_slot)
        self.OnReceiveRealData.connect(self.realdata_slot)  # 실시간 이벤트 연결
        self.OnReceiveChejanData.connect(self.chejan_slot)  # 종목 주문체결 관련한 이벤트

        ####### event loop를 실행하기 위한 변수모음
        self.login_event_loop = QEventLoop() #로그인 요청용 이벤트루프
        self.detail_account_info_event_loop = QEventLoop() # 예수금 요청용 이벤트루프
        self.calculator_event_loop = QEventLoop()
        #########################################

        ####### login
        self.block_signal_login_commConnect() #로그인 요청 시그널 포함

        ########### 전체 종목 관리
        self.all_stock_dict = {}
        ###########################
        ####### 계좌 관련된 변수
        self.account_num = ""
        self.account_info_dict = {}
        self.account_stock_dict = {} # unit stock
        self.account1_stock_dict = {}
        self.account2_stock_dict = {}
        self.not_account_stock_dict = {}
        self.deposit = 0 #예수금
        self.output_deposit = 0 #출력가능 금액
        self.total_profit_loss_money = 0 #총평가손익금액
        self.total_profit_loss_rate = 0.0 #총수익률(%)
        ########################################
        ######## 종목 정보 가져오기
        self.portfolio_stock_dict = {}
        self.jango_dict = {}
        ########################
        ########### 종목 분석 용
        self.calcul_data = []
        ##########################################
        ####### 요청 스크린 번호
        self.screen_my_info = "2000" #계좌 관련한 스크린 번호
        self.screen_calculation_stock = "4000" #계산용 스크린 번호
        self.screen_real_stock = "5000" #종목별 할당할 스크린 번호
        self.screen_meme_stock = "6000" #종목별 할당할 주문용스크린 번호
        self.screen_start_stop_real = "1000" #장 시작/종료 실시간 스크린번호
        ########################################

        # trading loop ########################################
        self.isTradingState = "None"
        self.setupSystemTrading()
        self.startSystemTrading()
        #########################################

    # 함수시작 ##############################################################################################
    # 함수 파트 : Logger ##########################################################################
    def set_logger(self):  # 로그 환경을 설정해주는 함수
        fomatter = logging.Formatter(
            '[%(levelname)s|%(lineno)s] %(asctime)s > %(message)s')  # 로그를 남길 방식으로 "[로그레벨|라인번호] 날짜 시간,밀리초 > 메시지" 형식의 포매터를 만든다

        logday = datetime.today().strftime("%Y%m%d")  # 로그 파일 네임에 들어갈 날짜를 만듬 (YYYYmmdd 형태)

        fileMaxByte = 1024 * 1024 * 100  # 파일 최대 용량인 100MB를 변수에 할당 (100MB, 102,400KB)
        fileHandler = logging.handlers.RotatingFileHandler('./log/stock_' + str(logday) + '.log', maxBytes=fileMaxByte,
                                                           backupCount=10)  # 파일에 로그를 출력하는 핸들러 (100MB가 넘으면 최대 10개까지 신규 생성)
        streamHandler = logging.StreamHandler()  # 콘솔에 로그를 출력하는 핸들러

        fileHandler.setFormatter(fomatter)  # 파일에 로그를 출력하는 핸들러에 포매터를 지정
        streamHandler.setFormatter(fomatter)  # 콘솔에 로그를 출력하는 핸들러에 포매터를 지정

        logger.addHandler(fileHandler)  # 로그 인스턴스에 파일에 로그를 출력하는 핸들러를 추가
        logger.addHandler(streamHandler)  # 로그 인스턴스에 콘솔에 로그를 출력하는 핸들러를 추가

        logger.setLevel(logging.INFO)  # 로그 레벨을 디버그로 만듬
        # logger.setLevel(logging.DEBUG)  # 로그 레벨을 디버그로 만듬

    def block_signal_login_commConnect(self):
        logger.debug("func : block_signal_login_commConnect")
        self.dynamicCall("CommConnect()") # 로그인 요청 시그널
        self.login_event_loop.exec_() # 이벤트루프 실행

    def login_slot(self, err_code):
        logger.debug("func : login_slot")
        logger.debug(errors(err_code)[1])
        #로그인 처리가 완료됐으면 이벤트 루프를 종료한다.
        self.login_event_loop.exit()

    def block_get_account_info(self):
        logger.debug("func : block_get_account_info")
        account_list = self.dynamicCall("GetLoginInfo(QString)", "ACCNO") # 계좌번호 반환
        logger.info("account_list : %s" % account_list)
        account_num = account_list.split(';')[0]
        self.account_num = account_num
        self.account_num = self.account # config.ini 에서 읽어온계좌
        logger.info("accout_num : %s" % self.account_num)
        # exit()

    def block_detail_account_info(self, sPrevNext="0"):
        logger.debug("func: block_detail_account_info")
        self.dynamicCall("SetInputValue(QString, QString)", "계좌번호", self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호", "0000")
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호입력매체구분", "00")
        self.dynamicCall("SetInputValue(QString, QString)", "조회구분", "1")
        self.dynamicCall("CommRqData(QString, QString, int, QString)", "예수금상세현황요청", "opw00001", sPrevNext, self.screen_my_info)
        self.detail_account_info_event_loop.exec_()

    def block_detail_account_mystock(self, sPrevNext="0"):
        logger.debug("func: block_detail_account_mystock")
        self.dynamicCall("SetInputValue(QString, QString)", "계좌번호", self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호", "0000")
        self.dynamicCall("SetInputValue(QString, QString)", "비밀번호입력매체구분", "00")
        self.dynamicCall("SetInputValue(QString, QString)", "조회구분", "1")
        self.dynamicCall("CommRqData(QString, QString, int, QString)", "계좌평가잔고내역요청", "opw00018", sPrevNext, self.screen_my_info)

        self.detail_account_info_event_loop.exec_()

    def not_concluded_account(self, sPrevNext="0"):
        logger.debug("func : not_concluded_account")
        self.dynamicCall("SetInputValue(QString, QString)", "계좌번호", self.account_num)
        self.dynamicCall("SetInputValue(QString, QString)", "체결구분", "1")
        self.dynamicCall("SetInputValue(QString, QString)", "매매구분", "0")
        self.dynamicCall("CommRqData(QString, QString, int, QString)", "실시간미체결요청", "opt10075", sPrevNext, self.screen_my_info)

        self.detail_account_info_event_loop.exec_()

    def stop_screen_cancel(self, sScrNo=None):
        logger.debug("func : stop_screen_cancel")
        self.dynamicCall("DisconnectRealData(QString)", sScrNo) # 스크린번호 연결 끊기

    def read_code_xls(self):
        logger.info("func : read_code")
        aPath = "D:/stocklab/bskiwoom/analysys/input/거래종목.xlsx"
        if os.path.exists(aPath): # 해당 경로에 파일이 있는지 체크한다.
            logger.info("aPath exists")
            df = pd.read_excel(aPath, names=["종목코드", "종목명", "EV10", "EV3H", "EV3L", "EV40", "PVOLIC", "거래여부"])
            logger.debug(df)

            for idx, row in df.iterrows(): #줄바꿈된 내용들이 한줄 씩 읽어와진다.
                stock_code = row[0][1:]
                stock_name = row[1]
                stock_EV10 = int(row[2])
                stock_EV3H = int(row[3])
                stock_EV3L = int(row[4])
                stock_EV40 = int(row[5])
                stock_PVOLIC = int(row[6])
                stock_decision = row[7]
                logger.debug(type(row[7]),stock_decision)
                if stock_decision == 1:
                    self.portfolio_stock_dict.update({stock_code:{"종목명":stock_name, "매도": "가능", "매수": "가능"}})
                else :
                    self.portfolio_stock_dict.update({stock_code: {"종목명": stock_name, "매도": "가능", "매수": "불가능"}})
            logger.debug("self.portfolio_stock_dict")
            logger.debug(self.portfolio_stock_dict)

    def screen_number_setting(self):
        logger.debug("func : screen_number_setting")
        screen_overwrite = []

        #계좌평가잔고내역에 있는 종목들
        for code in self.account_stock_dict.keys():
            if code not in screen_overwrite:
                screen_overwrite.append(code)

        #미체결에 있는 종목들
        for order_number in self.not_account_stock_dict.keys():
            code = self.not_account_stock_dict[order_number]['종목코드']

            if code not in screen_overwrite:
                screen_overwrite.append(code)

        #포트폴리로에 담겨있는 종목들
        for code in self.portfolio_stock_dict.keys():

            if code not in screen_overwrite:
                screen_overwrite.append(code)

        # 스크린번호 할당
        cnt = 0
        for code in screen_overwrite:

            temp_screen = int(self.screen_real_stock)
            meme_screen = int(self.screen_meme_stock)

            if (cnt % 50) == 0:
                temp_screen += 1
                self.screen_real_stock = str(temp_screen)

            if (cnt % 50) == 0:
                meme_screen += 1
                self.screen_meme_stock = str(meme_screen)

            if code in self.portfolio_stock_dict.keys():
                self.portfolio_stock_dict[code].update({"스크린번호": str(self.screen_real_stock)})
                self.portfolio_stock_dict[code].update({"주문용스크린번호": str(self.screen_meme_stock)})

            elif code not in self.portfolio_stock_dict.keys():
                self.portfolio_stock_dict.update({code: {"스크린번호": str(self.screen_real_stock), "주문용스크린번호": str(self.screen_meme_stock),
                                                 "매도": "가능","매수": "불가능"}})
            cnt += 1
        logger.info("Screen settion => self.portfolio_stock_dict")
        logger.info(self.portfolio_stock_dict)

    def day_kiwoom_db(self, code=None, date=None, sPrevNext="0"):
        logger.debug("func : day_kiwoom_db")
        QTest.qWait(3600) #3.6초마다 딜레이를 준다.

        self.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)
        self.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", "1")

        if date != None:
            self.dynamicCall("SetInputValue(QString, QString)", "기준일자", date)

        self.dynamicCall("CommRqData(QString, QString, int, QString)", "주식일봉차트조회", "opt10081", sPrevNext, self.screen_calculation_stock)  # Tr서버로 전송 -Transaction

        self.calculator_event_loop.exec_()

    def puttoRealDB(self,sCode,psd):
        logger.debug("enter puttoRealDB!!!")
        dbd = {}
        try :
            if self.portfolio_stock_dict[sCode]["매수"] == "가능":
                dbd.update({sCode:{}})
                # dbd[sCode].update([psd["체결시간"],psd["시가"],psd["고가"],psd["저가"],psd["현재가"],psd["거래량"]])

                dbd[sCode].update({"체결시간": psd["체결시간"]})
                dbd[sCode].update({"시가": psd["시가"]})
                dbd[sCode].update({"고가": psd["고가"]})
                dbd[sCode].update({"저가": psd["저가"]})
                dbd[sCode].update({"현재가": psd["현재가"]})
                dbd[sCode].update({"거래량": psd["거래량"]})

                ref = self.Fdb.reference() #기본 위치 지정
                users_ref = ref.child('bbsking1')
                users_ref.push({sCode:dbd,'used':False})
        except: {
            logger.error(EnvironmentError)
        }

            # dbd[sCode].update({"전일대비": psd[]})
            # dbd[sCode].update({"등락율": psd[]})
            # dbd[sCode].update({"(최우선)매도호가": psd[]})
            # dbd[sCode].update({"(최우선)매수호가": psdf})
            # dbd[sCode].update({"누적거래량": psd})

            # ref = db.reference() #기본 위치 지정
            # users_ref = ref.child(sCode)
            # users_ref.push({sCode:dbd})

            # logger.debug(self.Fdb)
            # dir = self.Fdb.reference() #기본 위치 지정
            # dir.update({'야구부':'임꺽정'})
            # ref.update({'A005930':[{'회사명':'삼성전자'},{'1':[[1],[2],[3]]},{'2':[[4],[5],[6]]}]})

            # ref = db.reference() #기본 위치 지정
            # users_ref = ref.child('bbsking1')
            # for item in users_ref.get():
            # snapshot = users_ref.child(item).get()
            # print(snapshot)
            # # type(snapshot) # dict
            # print(list(snapshot[sCode]))
            # type(snapshot[sCode]) # list
            # print(snapshot['used'])
            # if snapshot['used'] == False:
            #     users_ref.child(item).update({'used':True})
    ## 안쓰는 함수들 ######################################################################################
    def get_code_list_by_market(self, market_code):
        logger.debug("func : get_code_list_by_market")
        '''
        종목코드 리스트 받기
        #0:장내, 10:코스닥
        :param market_code: 시장코드 입력
        :return:
        '''
        code_list = self.dynamicCall("GetCodeListByMarket(QString)", market_code)
        code_list = code_list.split(';')[:-1]
        return code_list
    def calculator_fnc(self):
        logger.debug("func : calculator_fnc")
        '''
        종목 분석관련 func 모음
        :return:
        '''

        code_list = self.get_code_list_by_market("10")
        logger.debug("코스닥 갯수 %s " % len(code_list))

        for idx, code in enumerate(code_list):
            self.dynamicCall("DisconnectRealData(QString)", self.screen_calculation_stock)  # 스크린 연결 끊기

            logger.debug("%s / %s :  KOSDAQ Stock Code : %s is updating... " % (idx + 1, len(code_list), code))
            self.day_kiwoom_db(code=code)
    def read_code(self):
        logger.debug("func : read_code")
        if os.path.exists("stocklab/kiwoom/files/condition_stock.txt"): # 해당 경로에 파일이 있는지 체크한다.
            f = open("stocklab/kiwoom/files/condition_stock.txt", "r", encoding="utf8") # "r"을 인자로 던져주면 파일 내용을 읽어 오겠다는 뜻이다.
            #f = open("files/condition_stock.txt", "r", encoding="utf-16")  # "r"을 인자로 던져주면 파일 내용을 읽어 오겠다는 뜻이다.

            lines = f.readlines() #파일에 있는 내용들이 모두 읽어와 진다.
            for line in lines: #줄바꿈된 내용들이 한줄 씩 읽어와진다.
                if line != "":
                    ls = line.strip().split("\t")

                    stock_code = ls[0]
                    stock_name = ls[1]
                    #stock_price = int(ls[2].split("\n")[0])
                    stock_price = int(ls[2])
                    stock_price = abs(stock_price)
                    stock_buyDecision = int(ls[3])
                    stock_buyDecision = abs(stock_buyDecision)
                    stock_sellDecision = int(ls[4])
                    stock_sellDecision = abs(stock_sellDecision)

                    self.portfolio_stock_dict.update({stock_code:{"종목명":stock_name, "현재가":stock_price, "매수기준":stock_buyDecision, "매도기준":stock_sellDecision}})
                    #self.portfolio_stock_dict.update({stock_code: {"종목명": stock_name}})
            f.close()
    def merge_dict(self):
        logger.debug("func : merge_dict")
        self.all_stock_dict.update({"계좌평가잔고내역": self.account_stock_dict})
        self.all_stock_dict.update({'미체결종목': self.not_account_stock_dict})
        self.all_stock_dict.update({'포트폴리오종목': self.portfolio_stock_dict})
    def file_delete(self):
        logger.debug("func : file_delete")
        if os.path.isfile("stocklab/kiwoom/files/condition_stock.txt"):
            os.remove("stocklab/kiwoom/files/condition_stock.txt")
            ############################################################################
    def make_ConditionFile(self):
        logger.debug("func : make_ConditionFile")
        if os.path.exists("stocklab/kiwoom/files/condition_stock0.txt"): # 해당 경로에 파일이 있는지 체크한다.
            f = open("stocklab/kiwoom/files/condition_stock0.txt", "r", encoding="utf-16") # "r"을 인자로 던져주면 파일 내용을 읽어 오겠다는 뜻이다.

            code_list = []
            lines = f.readlines() #파일에 있는 내용들이 모두 읽어와 진다.
            for line in lines: #줄바꿈된 내용들이 한줄 씩 읽어와진다.
                if line != "":
                    ls = line.strip().split("\t")
                    code_list.append(ls[0][1:])
            f.close()

        logger.debug("갯수 %s " % len(code_list))
        for idx, code in enumerate(code_list):
            self.dynamicCall("DisconnectRealData(QString)", self.screen_calculation_stock)  # 스크린 연결 끊기

            logger.debug("%s / %s :  KOSDAQ Stock Code : %s is updating... " % (idx + 1, len(code_list), code))
            self.day_kiwoom_db(code=code)
    def sell_all(self):
        logger.debug("func : sell_all")
        for sCode in self.account_stock_dict.keys():
            asd = self.account_stock_dict[sCode]
            #meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
            if asd['매매가능수량'] > 0:
                order_success = self.dynamicCall(
                    "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                    ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode, asd['매매가능수량'], 0,
                     self.realType.SENDTYPE['거래구분']['시장가'], ""]
                )
                if order_success == 0:
                    logger.debug("매도주문 전달 성공")
                    del self.account_stock_dict[sCode]
                else:
                    logger.debug("매도주문 전달 실패")

        for sCode in self.jango_dict.keys():
            asd = self.jango_dict[sCode]
            #meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
            if asd['매매가능수량'] > 0:
                order_success = self.dynamicCall(
                    "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                    ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode, asd['보유수량'], 0,
                     self.realType.SENDTYPE['거래구분']['시장가'], ""]
                )
                if order_success == 0:
                    logger.debug("매도주문 전달 성공")
                    del self.account_stock_dict[sCode]
                else:
                    logger.debug("매도주문 전달 실패")
    ###################################################################################################################

    ## CallBack 함수들... ##############################################################################################
    #송수신 메세지 get
    def msg_slot(self, sScrNo, sRQName, sTrCode, msg):
        logger.debug("func : msg_slot")
        logger.debug("")
        logger.debug("스크린: %s, 요청이름: %s, tr코드: %s --- %s" %(sScrNo, sRQName, sTrCode, msg))

    def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):
        logger.debug("func : trdata_slot")
        if sRQName == "예수금상세현황요청":
            logger.debug("func : trdata_slot => 예수금상세현황요청")
            deposit = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "예수금")
            self.deposit = int(deposit)

            # use_money = float(self.deposit) * self.use_money_percent
            # self.use_money = int(use_money)
            # self.use_money = self.use_money / 4

            output_deposit = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "출금가능금액")
            self.output_deposit = int(output_deposit)

            logger.info("예수금 : %s" % self.output_deposit)

            self.stop_screen_cancel(self.screen_my_info)

            self.detail_account_info_event_loop.exit()

        elif sRQName == "계좌평가잔고내역요청":
            logger.debug("func : trdata_slot => 계좌평가잔고내역요청")
            total_buy_money = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총매입금액")
            self.total_buy_money = int(total_buy_money)
            total_profit_loss_money = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총평가손익금액")
            self.total_profit_loss_money = int(total_profit_loss_money)
            total_profit_loss_rate = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "총수익률(%)")
            self.total_profit_loss_rate = float(total_profit_loss_rate)
            logger.debug("계좌평가잔고내역요청 싱글데이터 : %s - %s - %s" % (total_buy_money, total_profit_loss_money, total_profit_loss_rate))

            rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
            for i in range(rows):
                code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목번호")  # 출력 : A039423 // 알파벳 A는 장내주식, J는 ELW종목, Q는 ETN종목
                code = code.strip()[1:]

                code_nm = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")  # 출럭 : 한국기업평가
                stock_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "보유수량")  # 보유수량 : 000000000000010
                buy_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입가")  # 매입가 : 000000000054100
                learn_rate = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "수익률(%)")  # 수익률 : -000000001.94
                current_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")  # 현재가 : 000000003450
                total_chegual_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매입금액")
                possible_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "매매가능수량")
                today_buyquantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"금일매수수량")
                today_sellquantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,"금일매도수량")

                logger.debug("종목코드: %s - 종목명: %s - 보유수량: %s - 매매가능수량: %s - 금일매수수량: %s - 금일매도수량: %s - 매입가:%s - 수익률: %s - 현재가: %s" % (
                    code, code_nm, stock_quantity, possible_quantity, today_buyquantity, today_sellquantity, buy_price, learn_rate, current_price))

                if code in self.account_stock_dict:  # dictionary 에 해당 종목이 있나 확인
                    pass
                else:
                    self.account_stock_dict[code] = {}

                code_nm = code_nm.strip()
                stock_quantity = int(stock_quantity.strip())
                buy_price = int(buy_price.strip())
                learn_rate = float(learn_rate.strip())
                current_price = int(current_price.strip())
                total_chegual_price = int(total_chegual_price.strip())
                possible_quantity = int(possible_quantity.strip())-int(today_buyquantity.strip())
                today_buyquantity = int(today_buyquantity.strip())
                today_sellquantity = int(today_sellquantity.strip())

                self.account_stock_dict[code].update({"종목명": code_nm})
                self.account_stock_dict[code].update({"보유수량": stock_quantity})
                self.account_stock_dict[code].update({"매입가": buy_price})
                self.account_stock_dict[code].update({"수익률": learn_rate})
                self.account_stock_dict[code].update({"현재가": current_price})
                self.account_stock_dict[code].update({"매입금액": total_chegual_price})
                self.account_stock_dict[code].update({'매매가능수량' : possible_quantity})
                self.account_stock_dict[code].update({'금일매수수량': today_buyquantity})
                self.account_stock_dict[code].update({'금일매도수량': today_sellquantity})
                self.account_stock_dict[code].update({'매도': "가능"})

            logger.info("sPreNext : %s" % sPrevNext)

            if sPrevNext == "2":
                self.detail_account_mystock(sPrevNext="2")
            else:
                logger.debug("계좌에 가지고 있는 종목은 %s " % rows)
                self.account_info_dict.update(
                    {self.account_num:
                        {
                            "투입금액": self.use_money,
                            "단위금액": self.unit_money,
                            "최대거래종목수": self.maxStockNum,
                            "총매입금액": self.total_buy_money,
                            "총평가손익금액": self.total_profit_loss_money,
                            "총수익률(%)": self.total_profit_loss_rate,
                            "보유종목수": rows,
                            "매수가능": "가능"
                        }
                    })
                if rows >= self.account_info_dict[self.account_num]["최대거래종목수"]:
                    self.account_info_dict[self.account_num].update({"매수가능": "불가능"})
                logger.info(self.account_info_dict)
                self.detail_account_info_event_loop.exit()

        elif sRQName == "실시간미체결요청":
            logger.debug("func : trdata_slot => 실시간미체결요청")
            rows = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
            for i in range(rows):
                code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목코드")
                code_nm = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "종목명")
                order_no = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "주문번호")
                order_status = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                                "주문상태")  # 접수,확인,체결
                order_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                                  "주문수량")
                order_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                               "주문가격")
                order_gubun = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                               "주문구분")  # -매도, +매수, -매도정정, +매수정정
                not_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                                "미체결수량")
                ok_quantity = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i,
                                               "체결량")

                code = code.strip()
                code_nm = code_nm.strip()
                order_no = int(order_no.strip())
                order_status = order_status.strip()
                order_quantity = int(order_quantity.strip())
                order_price = int(order_price.strip())
                order_gubun = order_gubun.strip().lstrip('+').lstrip('-')
                not_quantity = int(not_quantity.strip())
                ok_quantity = int(ok_quantity.strip())

                if order_no in self.not_account_stock_dict:
                    pass
                else:
                    self.not_account_stock_dict[order_no] = {}

                self.not_account_stock_dict[order_no].update({'종목코드': code})
                self.not_account_stock_dict[order_no].update({'종목명': code_nm})
                self.not_account_stock_dict[order_no].update({'주문번호': order_no})
                self.not_account_stock_dict[order_no].update({'주문상태': order_status})
                self.not_account_stock_dict[order_no].update({'주문수량': order_quantity})
                self.not_account_stock_dict[order_no].update({'주문가격': order_price})
                self.not_account_stock_dict[order_no].update({'주문구분': order_gubun})
                self.not_account_stock_dict[order_no].update({'미체결수량': not_quantity})
                self.not_account_stock_dict[order_no].update({'체결량': ok_quantity})

                logger.info("미체결 종목 : %s "  % self.not_account_stock_dict[order_no])

            self.detail_account_info_event_loop.exit()

        elif sRQName == "주식일봉차트조회":
            logger.info("func : trdata_slot => 주식일봉차트조회")
            code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목코드")
            code = code.strip()
            # data = self.dynamicCall("GetCommDataEx(QString, QString)", sTrCode, sRQName)
            # [[‘’, ‘현재가’, ‘거래량’, ‘거래대금’, ‘날짜’, ‘시가’, ‘고가’, ‘저가’. ‘’], [‘’, ‘현재가’, ’거래량’, ‘거래대금’, ‘날짜’, ‘시가’, ‘고가’, ‘저가’, ‘’]. […]]

            cnt = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
            logger.info("남은 일자 수 %s" % cnt)
            for i in range(cnt):
                data = []

                current_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가")  # 출력 : 000070
                value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래량")  # 출력 : 000070
                trading_value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래대금")  # 출력 : 000070
                date = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "일자")  # 출력 : 000070
                start_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "시가")  # 출력 : 000070
                high_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "고가")  # 출력 : 000070
                low_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "저가")  # 출력 : 000070

                data.append("")
                data.append(current_price.strip())
                data.append(value.strip())
                data.append(trading_value.strip())
                data.append(date.strip())
                data.append(start_price.strip())
                data.append(high_price.strip())
                data.append(low_price.strip())
                data.append("")
                self.calcul_data.append(data.copy())

            if sPrevNext == "2":
                self.day_kiwoom_db(code=code, sPrevNext=sPrevNext)
            else:
                logger.debug("총 일수 %s" % len(self.calcul_data))

                self.calcul_data.clear()
                self.calculator_event_loop.exit()

    # 실시간 데이터 얻어오기
    def realdata_slot(self, sCode, sRealType, sRealData):
        logger.debug("func : realdata_slot")
        if sRealType == "장시작시간":
            fid = self.realType.REALTYPE[sRealType]['장운영구분']  # (0:장시작전, 2:장종료전(20분), 3:장시작, 4,8:장종료(30분), 9:장마감)
            value = self.dynamicCall("GetCommRealData(QString, int)", sCode, fid)

            if value == '0':
                logger.info("장 시작 전")
            elif value == '3':
                logger.info("장 시작")
            elif value == "2":
                logger.info("장 종료, 동시호가로 넘어감")
            elif value == "4":
                logger.info("3시30분 장 종료")
                for code in self.portfolio_stock_dict.keys():
                    self.dynamicCall("SetRealRemove(QString, QString)", self.portfolio_stock_dict[code]['스크린번호'], code)
                QTest.qWait(5000)
                exit()

        elif sRealType == "주식체결":

            a = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['체결시간'])  # 출력 HHMMSS
            b = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['현재가'])  # 출력 : +(-)2520
            b = abs(int(b))

            c = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['전일대비'])  # 출력 : +(-)2520
            c = abs(int(c))

            d = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['등락율'])  # 출력 : +(-)12.98
            d = float(d)

            e = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['(최우선)매도호가'])  # 출력 : +(-)2520
            e = abs(int(e))

            f = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['(최우선)매수호가'])  # 출력 : +(-)2515
            f = abs(int(f))

            g = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['거래량'])  # 출력 : +240124  매수일때, -2034 매도일 때
            g = abs(int(g))

            h = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['누적거래량'])  # 출력 : 240124
            h = abs(int(h))

            i = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['고가'])  # 출력 : +(-)2530
            i = abs(int(i))

            j = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['시가'])  # 출력 : +(-)2530
            j = abs(int(j))

            k = self.dynamicCall("GetCommRealData(QString, int)", sCode, self.realType.REALTYPE[sRealType]['저가'])  # 출력 : +(-)2530
            k = abs(int(k))

            if sCode not in self.portfolio_stock_dict:
                logging.error(" 포트폴리오에 없는종목 %s" % sCode)
                return
                # self.portfolio_stock_dict.update({sCode:{}})

            self.portfolio_stock_dict[sCode].update({"체결시간": a})
            self.portfolio_stock_dict[sCode].update({"현재가": b})
            self.portfolio_stock_dict[sCode].update({"전일대비": c})
            self.portfolio_stock_dict[sCode].update({"등락율": d})
            self.portfolio_stock_dict[sCode].update({"(최우선)매도호가": e})
            self.portfolio_stock_dict[sCode].update({"(최우선)매수호가": f})
            self.portfolio_stock_dict[sCode].update({"거래량": g})
            self.portfolio_stock_dict[sCode].update({"누적거래량": h})
            self.portfolio_stock_dict[sCode].update({"고가": i})
            self.portfolio_stock_dict[sCode].update({"시가": j})
            self.portfolio_stock_dict[sCode].update({"저가": k})

            self.puttoRealDB(sCode,self.portfolio_stock_dict[sCode])

            if sCode in self.account_stock_dict.keys(): # and sCode not in self.jango_dict.keys():
                asd = self.account_stock_dict[sCode]
                psd = self.portfolio_stock_dict[sCode]
                logger.debug("매도콜백")
                logger.debug(asd)

                meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
                if sCode in self.account2_stock_dict:
                    if asd['매도'] == "가능" and asd['보유수량'] > 0 and asd['금일매도수량'] == 0 and meme_rate > 30:  # 손익절 매도

                        order_success = self.dynamicCall(
                            "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                            ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode,
                             int(asd['보유수량'] / 2), 0, self.realType.SENDTYPE['거래구분']['시장가'], ""]
                        )
                        if order_success == 0:
                            logger.info("매도주문 전달 성공")
                            self.slack.send_msg(msg="bsking1 매도주문 전달 성공")
                            asd.update({'매도': "불가능"})
                            del self.account2_stock_dict[sCode]
                            # del self.portfolio_stock_dict[sCode]
                        else:
                            logger.info("매도주문 전달 실패")

                # meme_rate = (b - asd['매입가']) / asd['매입가'] * 100
                if asd['매도'] == "가능" and asd['보유수량'] > 0 and meme_rate < -15 : # 손절 전액매도
                    order_success = self.dynamicCall(
                        "SendOrder(QString, QString, QString, int, QString, int, int, QString, QString)",
                        ["신규매도", self.portfolio_stock_dict[sCode]["주문용스크린번호"], self.account_num, 2, sCode, asd['보유수량'], 0, self.realType.SENDTYPE['거래구분']['시장가'], ""]
                    )
                    if order_success == 0:
                        logger.info("매도주문 전달 성공")
                        self.slack.send_msg(msg="bsking1 매도주문 전달 성공")
                        asd.update({'매도': "불가능"})
                        del self.account_stock_dict[sCode]
                        if sCode in self.account2_stock_dict:
                            del self.account2_stock_dict[sCode]
                        del self.portfolio_stock_dict[sCode]
                    else:
                        logger.info("매도주문 전달 실패")

    # 실시간 체결 정보
    def chejan_slot(self, sGubun, nItemCnt, sFidList):
        logger.debug("func : chejan_slot")
        if int(sGubun) == 0: #주문체결
            account_num = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['계좌번호'])
            sCode = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['종목코드'])[1:]
            stock_name = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['종목명'])
            stock_name = stock_name.strip()

            origin_order_number = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['원주문번호'])  # 출력 : defaluse : "000000"
            order_number = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문번호'])  # 출럭: 0115061 마지막 주문번호

            order_status = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문상태'])  # 출력: 접수, 확인, 체결
            order_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문수량'])  # 출력 : 3
            order_quan = int(order_quan)

            order_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문가격'])  # 출력: 21000
            order_price = int(order_price)

            not_chegual_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['미체결수량'])  # 출력: 15, default: 0
            not_chegual_quan = int(not_chegual_quan)

            order_gubun = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문구분'])  # 출력: -매도, +매수
            order_gubun = order_gubun.strip().lstrip('+').lstrip('-')

            chegual_time_str = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['주문/체결시간'])  # 출력: '151028'

            chegual_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['체결가'])  # 출력: 2110  default : ''
            if chegual_price == '':
                chegual_price = 0
            else:
                chegual_price = int(chegual_price)

            chegual_quantity = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['체결량'])  # 출력: 5  default : ''
            if chegual_quantity == '':
                chegual_quantity = 0
            else:
                chegual_quantity = int(chegual_quantity)

            current_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['현재가'])  # 출력: -6000
            current_price = abs(int(current_price))

            first_sell_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['(최우선)매도호가'])  # 출력: -6010
            first_sell_price = abs(int(first_sell_price))

            first_buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['주문체결']['(최우선)매수호가'])  # 출력: -6000
            first_buy_price = abs(int(first_buy_price))

            ######## 새로 들어온 주문이면 주문번호 할당
            if order_number not in self.not_account_stock_dict.keys():
                self.not_account_stock_dict.update({order_number: {}})

            self.not_account_stock_dict[order_number].update({"종목코드": sCode})
            self.not_account_stock_dict[order_number].update({"주문번호": order_number})
            self.not_account_stock_dict[order_number].update({"종목명": stock_name})
            self.not_account_stock_dict[order_number].update({"주문상태": order_status})
            self.not_account_stock_dict[order_number].update({"주문수량": order_quan})
            self.not_account_stock_dict[order_number].update({"주문가격": order_price})
            self.not_account_stock_dict[order_number].update({"미체결수량": not_chegual_quan})
            self.not_account_stock_dict[order_number].update({"원주문번호": origin_order_number})
            self.not_account_stock_dict[order_number].update({"주문구분": order_gubun})
            self.not_account_stock_dict[order_number].update({"주문/체결시간": chegual_time_str})
            self.not_account_stock_dict[order_number].update({"체결가": chegual_price})
            self.not_account_stock_dict[order_number].update({"체결량": chegual_quantity})
            self.not_account_stock_dict[order_number].update({"현재가": current_price})
            self.not_account_stock_dict[order_number].update({"(최우선)매도호가": first_sell_price})
            self.not_account_stock_dict[order_number].update({"(최우선)매수호가": first_buy_price})

        elif int(sGubun) == 1: #잔고

            account_num = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['계좌번호'])
            sCode = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['종목코드'])[1:]

            stock_name = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['종목명'])
            stock_name = stock_name.strip()

            current_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['현재가'])
            current_price = abs(int(current_price))

            stock_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['보유수량'])
            stock_quan = int(stock_quan)

            like_quan = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['주문가능수량'])
            like_quan = int(like_quan)

            buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['매입단가'])
            buy_price = abs(int(buy_price))

            total_buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['총매입가']) # 계좌에 있는 종목의 총매입가
            total_buy_price = int(total_buy_price)

            meme_gubun = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['매도매수구분'])
            meme_gubun = self.realType.REALTYPE['매도수구분'][meme_gubun] # 1: 매수, 0: 매도(?)

            first_sell_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['(최우선)매도호가'])
            first_sell_price = abs(int(first_sell_price))

            first_buy_price = self.dynamicCall("GetChejanData(int)", self.realType.REALTYPE['잔고']['(최우선)매수호가'])
            first_buy_price = abs(int(first_buy_price))

            if sCode not in self.jango_dict.keys():
                self.jango_dict.update({sCode:{}})

            self.jango_dict[sCode].update({"현재가": current_price})
            self.jango_dict[sCode].update({"종목코드": sCode})
            self.jango_dict[sCode].update({"종목명": stock_name})
            self.jango_dict[sCode].update({"보유수량": stock_quan})
            self.jango_dict[sCode].update({"주문가능수량": like_quan})
            self.jango_dict[sCode].update({"매입단가": buy_price})
            self.jango_dict[sCode].update({"총매입가": total_buy_price})
            self.jango_dict[sCode].update({"매도매수구분": meme_gubun})
            self.jango_dict[sCode].update({"(최우선)매도호가": first_sell_price})
            self.jango_dict[sCode].update({"(최우선)매수호가": first_buy_price})

            if stock_quan == 0:
                del self.jango_dict[sCode]
                #self.slack.send_msg(msg=("%s 매도완료"%self.jango_dict[sCode]["종목명"]))
                logger.debug("매도완료")
            else :
                #self.slack.send_msg(msg=("%s 체결 %s주" %(self.jango_dict[sCode]["종목명"],stock_quan)))
                #logger.debug("%s 체결 %s주" %(self.jango_dict[sCode]["종목명"],stock_quan))
                logger.debug("매매체결")

    ##########################################################################################################
    def setupSystemTrading(self):
        try:
            logger.info("setupSystemTrading 시작")
            if 0 :
                #  self.testFirebaseDB()
                logger.info("setupSystemTrading 끝")
                exit()

            # self.account_num
            self.block_get_account_info()  # 계좌번호 가져오기
            # self.deposit : 예수금, self.output_deposit :출금가능금액 // self.use_money?
            self.block_detail_account_info()  # 예수금 요청 시그널 포함
            #self.total_buy_money :총매입금액, self.total_profit_loss_money :총평가손익금액, self.total_profit_loss_rate : 총수익률(%)
            # account_stock_dict[종목코드] : 종목명: %s - 보유수량: %s - 매입가:%s - 수익률: %s - 현재가: %s
            self.block_detail_account_mystock()  # 계좌평가잔고내역 요청 시그널 포함
            # not_account_stock_dict[order_no] : 종목코드 종목명 주문번호 주문상태 주문수량 주문가격 주문구분 미체결수량 체결량
            QTimer.singleShot(5000, self.not_concluded_account)  # 5초 뒤에 미체결 종목들 가져오기 실행
            QTest.qWait(10000)
            self.isTradingState = "OnTrading"
            # portfolio_stock_dict[종목명] : 현재가 매수기준 매도기준
            # self.read_code()
            self.read_code_xls()
             # 번호할당 portfolio_stock_dict <- portfolio_stock_dict + account_stock_dict + not_account_stock_dict
            self.screen_number_setting()
            QTest.qWait(5000)

            t_now = datetime.now()
            t_9 = t_now.replace(hour=9, minute=0, second=0, microsecond=0)
            t_start = t_now.replace(hour=9, minute=5, second=0, microsecond=0)
            t_sell = t_now.replace(hour=15, minute=00, second=0, microsecond=0)
            t_exit = t_now.replace(hour=15, minute=20, second=0, microsecond=0)
            today = datetime.today().weekday()
            if today == 5 or today == 6:  # 토요일이나 일요일이면 자동 종료
                logger.info("Today is Saturday or Sunday.")
                exit()

            if t_exit < t_now:  # PM 03:20 ~ :프로그램 종료
                logger.info("PM 03:20 ~ :프로그램 종료!")
                if 0 :
                    self.isTradingState = "MakeFile"
                    self.file_delete()
                    self.make_ConditionFile()
                exit()
            time.sleep(3)

            logger.info('실시간 수신 관련 함수')
            logger.debug(self.portfolio_stock_dict)
            # 실시간 수신 관련 함수
            self.dynamicCall("SetRealReg(QString, QString, QString, QString)", self.screen_start_stop_real, '',
                             self.realType.REALTYPE['장시작시간']['장운영구분'], "0")

            # exit()

            for code in self.portfolio_stock_dict.keys():
                screen_num = self.portfolio_stock_dict[code]['스크린번호']
                fids = self.realType.REALTYPE['주식체결']['체결시간']
                self.dynamicCall("SetRealReg(QString, QString, QString, QString)", screen_num, code, fids, "1")

        except Exception as ex:
            logger.debug('`main -> exception! ' + str(ex) + '`')

    def startSystemTrading(self):
        # Thread loop ########################################
        h1 = Thread1(self,logger)
        h1.start()
        #########################################
        pass


from django.conf.urls.defaults import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from resume.views import index, work,projects,skills,courses,home
admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'personal_site.views.home', name='home'),
    # url(r'^personal_site/', include('personal_site.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
    url(r'^$',index),
    url(r'^work/', work),
    url(r'^home/',home),
    url(r'^courses/',courses),
    url(r'^projects/',projects),
    url(r'^skills/',skills),
    # static

)
urlpatterns += staticfiles_urlpatterns()


import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-10,9,20)
y = x**3
z = x**2

# fig,axs = plt.subplot()
""" figure = plt.figure()

axes_cube = figure.add_axes([0.1,0.1,0.8,0.8])

axes_cube.plot(x,y,"o-b")
axes_cube.set_xlabel("X Axis")
axes_cube.set_ylabel("Y Axis")
axes_cube.set_title("Cube")

axes_squere = figure.add_axes([0.15,0.6,0.25,0.25])

axes_squere.plot(x,z,"o-r")
axes_squere.set_xlabel("X Axis")
axes_squere.set_ylabel("Y Axis")
axes_squere.set_title("Squere") """

""" figure = plt.figure()

axes = figure.add_axes([0,0,1,1])

axes.plot(x,z, label="Squere")
axes.plot(x,y, label="Cube")
axes.legend(loc=4)
 """

fig,axes = plt.subplots(nrows=2,ncols=1, figsize=(8,8))
axes[0].plot(x,y)
axes[0].set_title("Cube")

axes[1].plot(x,z)
axes[1].set_title("Squere")

plt.tight_layout()
fig.savefig("figure1.pdf")

plt.show()