import logging
from dataclasses import dataclass
from typing import Dict, List, Optional, Tuple, Union
import numpy as np
from table_extractor.model.table import (
    BorderBox,
    Cell,
    CellLinked,
    GridCell,
    GridCol,
    GridRow,
    GridTable,
    StructuredTable,
)
from sklearn.cluster import DBSCAN
LOGGER = logging.getLogger(__name__)

@dataclass
class MutableParameter:
    param: int

@dataclass
class MutableBox:
    orig: Union[BorderBox, Cell]
    top_left_x: MutableParameter
    top_left_y: MutableParameter
    bottom_right_x: MutableParameter
    bottom_right_y: MutableParameter

def _match_cells_and_table(table: GridTable, cells: List[Cell]):
    not_matched = []
    for cell in cells:
        row_num = None
        for r_idx, row in enumerate(table.rows):
            if row.box_is_inside_another(cell):
                row_num = r_idx
                break
        col_num = None
        for c_idx, col in enumerate(table.cols):
            if col.box_is_inside_another(cell):
                col_num = c_idx
                break
        if row_num is not None and col_num is not None:
            g_cell = table.cells[row_num * len(table.cols) + col_num]
            if not g_cell.box_is_inside_another(cell):
                not_matched.append(cell)
            g_cell.cells.append(cell)
        else:
            not_matched.append(cell)

    return not_matched

def _merge_closest_cells(g_cells: List[GridCell]):
    for g_cell in g_cells:
        cells = g_cell.cells.copy()
        new_cells = []
        while len(cells) > 0:
            curr_cell = cells.pop()
            for orig_cell in cells:
                if curr_cell.box_is_inside_another(orig_cell, 0.05):
                    curr_cell = curr_cell.merge(orig_cell)
                    cells.remove(orig_cell)
            new_cells.append(curr_cell)
        g_cell.cells = new_cells

def _find_gaps_in_zone(
    line: List[bool], zone: Tuple[int, int]
) -> List[List[int]]:
    gaps = []
    curr_gap = []
    for point_idx in range(zone[0], zone[1]):
        if line[point_idx] and curr_gap:
            curr_gap.append(point_idx - 1)
            gaps.append(curr_gap)
            curr_gap = []
        if not line[point_idx] and not curr_gap:
            curr_gap.append(point_idx)
    if curr_gap:
        curr_gap.append(zone[1])
        gaps.append(curr_gap)
    return gaps

def _get_line_coord_from_gaps(gaps: List[List[int]]) -> List[int]:
    return [(gap[0] + gap[1]) // 2 for gap in gaps]

def find_grid_table(h_lines, v_lines) -> GridTable:
    cells: List[GridCell] = []
    rows: List[GridRow] = []
    cols: List[GridCol] = []
    prev_h_line = h_lines[0]
    for h_idx, h_line in enumerate(h_lines[1:]):
        if h_idx >= len(rows):
            curr_row = GridRow(
                top_left_x=v_lines[0],
                top_left_y=prev_h_line,
                bottom_right_x=v_lines[-1],
                bottom_right_y=h_line,
            )
            rows.append(curr_row)
        else:
            curr_row = rows[h_idx]

        prev_v_line = v_lines[0]
        for v_idx, v_line in enumerate(v_lines[1:]):
            if v_idx >= len(cols):
                curr_col = GridCol(
                    top_left_x=prev_v_line,
                    top_left_y=h_lines[0],
                    bottom_right_x=v_line,
                    bottom_right_y=h_lines[-1],
                )
                cols.append(curr_col)
            else:
                curr_col = cols[v_idx]
            cell = GridCell(
                top_left_x=prev_v_line,
                bottom_right_x=v_line,
                top_left_y=prev_h_line,
                bottom_right_y=h_line,
                row=h_idx,
                col=v_idx,
            )
            curr_row.g_cells.append(cell)
            curr_col.g_cells.append(cell)
            cells.append(cell)
            prev_v_line = v_line
        prev_h_line = h_line
    grid_table = GridTable(rows=rows, cols=cols, cells=cells)
    return grid_table

def _find_lines(
    table_bbox: BorderBox, cells: List[Cell], image_shape: Tuple[int, int]
):
    if not cells:
        return [], []
    h_proj = [False for _ in range(0, image_shape[1])]
    v_proj = [False for _ in range(0, image_shape[0])]

    for cell in cells:
        h_proj[cell.top_left_x : cell.bottom_right_x + 1] = [
            True for _ in range(cell.top_left_x, cell.bottom_right_x + 1)
        ]
        v_proj[cell.top_left_y : cell.bottom_right_y + 1] = [
            True for _ in range(cell.top_left_y, cell.bottom_right_y + 1)
        ]

    v_gaps = _find_gaps_in_zone(
        h_proj, (table_bbox.top_left_x, table_bbox.bottom_right_x)
    )
    v_line_coords = _get_line_coord_from_gaps(v_gaps)

    h_gaps = _find_gaps_in_zone(
        v_proj, (table_bbox.top_left_y, table_bbox.bottom_right_y)
    )
    h_line_coords = _get_line_coord_from_gaps(h_gaps)
    return h_line_coords, v_line_coords

def _actualize_line_separators(
    table: GridTable, image_shape: Tuple[int, int]
) -> Tuple[List[int], List[int]]:
    span_candidates: Dict[int, GridCell] = {}
    for g_cell in table.cells:
        if len(g_cell.cells) > 1:
            span_candidates[len(table.cols) * g_cell.row + g_cell.col] = g_cell

    if not span_candidates:
        return [], []

    col_candidates = {}
    for g_cell in span_candidates.values():
        col_candidates[g_cell.col] = table.cols[g_cell.col]

    row_candidates = {}
    for g_cell in span_candidates.values():
        row_candidates[g_cell.row] = table.rows[g_cell.row]

    v_lines_to_add = []
    h_lines_to_add = []
    for cand_col in col_candidates.values():
        v_lines = []
        for g_cell in cand_col.g_cells:
            _, v_cell_lines = _find_lines(g_cell, g_cell.cells, image_shape)
            if v_cell_lines:
                min_v_cells = min([cell.top_left_x for cell in g_cell.cells])
                max_v_cells = max(
                    [cell.bottom_right_x for cell in g_cell.cells]
                )
                v_cell_lines = list(
                    filter(
                        lambda line: min_v_cells < line < max_v_cells,
                        v_cell_lines,
                    )
                )
            v_lines.append(v_cell_lines)
        g_cell_v_line = list(zip(cand_col.g_cells, v_lines))
        cand_v_sort = list(
            filter(
                lambda x: x[3],
                sorted(
                    [
                        (idx, len(v_cell_lines), g_cell, v_cell_lines)
                        for idx, (g_cell, v_cell_lines) in enumerate(
                            g_cell_v_line
                        )
                    ],
                    key=lambda x: (x[1], x[2].top_left_y),
                ),
            )
        )

        i = 0
        while i < len(cand_v_sort):
            idx, l, g_cell, v_cell_lines = cand_v_sort[i]
            if not l:
                i += 1
                continue
            cand_g_cells = g_cell.cells.copy()
            new_v_lines = v_cell_lines
            count_not_broken = 0
            for j in range(i + 1, len(cand_v_sort)):
                jdx, _, cand_j, v_lines_j = cand_v_sort[j]
                # Try compute common v_lines
                cells_to_check = cand_g_cells.copy()
                cells_to_check.extend(cand_j.cells)
                zone = BorderBox(
                    top_left_x=g_cell.top_left_x,
                    top_left_y=g_cell.top_left_y,
                    bottom_right_x=g_cell.bottom_right_x,
                    bottom_right_y=cand_j.bottom_right_y,
                )
                _, v = _find_lines(zone, cells_to_check, image_shape)
                if v:
                    min_v_cells = min(
                        [cell.top_left_x for cell in cells_to_check]
                    )
                    max_v_cells = max(
                        [cell.bottom_right_x for cell in cells_to_check]
                    )
                    v = list(
                        filter(
                            lambda line: min_v_cells < line < max_v_cells, v
                        )
                    )
                if len(v) >= len(v_cell_lines):
                    cand_g_cells = cells_to_check
                    new_v_lines = v
                    count_not_broken += 1
                else:
                    break
            i += count_not_broken + 1
            v_lines_to_add.extend(new_v_lines)

    for cand_row in row_candidates.values():
        h_lines = []
        for g_cell in cand_row.g_cells:
            h_cell_lines, _ = _find_lines(g_cell, g_cell.cells, image_shape)
            if h_cell_lines:
                min_h_cells = min([cell.top_left_y for cell in g_cell.cells])
                max_h_cells = max(
                    [cell.bottom_right_y for cell in g_cell.cells]
                )
                h_cell_lines = list(
                    filter(
                        lambda line: min_h_cells < line < max_h_cells,
                        h_cell_lines,
                    )
                )
            h_lines.append(h_cell_lines)
        g_cell_h_line = list(zip(cand_row.g_cells, h_lines))
        cand_h_sort = sorted(
            [
                (idx, len(h_cell_lines), g_cell, h_cell_lines)
                for idx, (g_cell, h_cell_lines) in enumerate(g_cell_h_line)
            ],
            key=lambda x: (x[1], x[2].top_left_y),
        )

        i = 0
        while i < len(cand_h_sort):
            idx, l, g_cell, h_cell_lines = cand_h_sort[i]
            if not l:
                i += 1
                continue
            cand_g_cells = g_cell.cells.copy()
            new_h_lines = h_cell_lines
            count_not_broken = 0
            for j in range(i + 1, len(cand_h_sort)):
                jdx, _, cand_j, h_lines_j = cand_h_sort[j]
                # Try compute common v_lines
                cells_to_check = cand_g_cells.copy()
                cells_to_check.extend(cand_j.cells)
                zone = BorderBox(
                    top_left_x=g_cell.top_left_x,
                    top_left_y=g_cell.top_left_y,
                    bottom_right_x=g_cell.bottom_right_x,
                    bottom_right_y=cand_j.bottom_right_y,
                )
                h, _ = _find_lines(zone, cells_to_check, image_shape)
                if h:
                    min_h_cells = min(
                        [cell.top_left_y for cell in cells_to_check]
                    )
                    max_h_cells = max(
                        [cell.bottom_right_y for cell in cells_to_check]
                    )
                    h = list(
                        filter(
                            lambda line: min_h_cells < line < max_h_cells, h
                        )
                    )
                if len(h) >= len(h_cell_lines):
                    cand_g_cells = cells_to_check
                    new_h_lines = h
                    count_not_broken += 1
                else:
                    break
            i += count_not_broken + 1
            h_lines_to_add.extend(new_h_lines)
    return list(set(v_lines_to_add)), list(set(h_lines_to_add))

def reconstruct_table_from_grid(
    grid_table: GridTable, cells: List[Cell]
) -> Tuple[Optional[StructuredTable], List[Cell]]:
    not_matched = []
    linked_cells = []
    grid_cells_dict = {}
    for g_cell in grid_table.cells:
        grid_cells_dict[
            g_cell.row * len(grid_table.cols) + g_cell.col
        ] = g_cell
    for cell in cells:
        rows = []
        for r_idx, row in enumerate(grid_table.rows):
            if row.box_is_inside_another(cell, 0.0):
                rows.append((r_idx, row))
        cols = []
        for c_idx, col in enumerate(grid_table.cols):
            if col.box_is_inside_another(cell, 0.0):
                cols.append((c_idx, col))
        matched_cells = []
        for row in rows:
            for col in cols:
                if grid_cells_dict.get(row[0] * len(grid_table.cols) + col[0]):
                    matched_cells.append(grid_cells_dict.pop(row[0] * len(grid_table.cols) + col[0]))
        if matched_cells:
            linked_cells.append(
                CellLinked(
                    top_left_y=min([c.top_left_y for c in matched_cells]),
                    top_left_x=min([c.top_left_x for c in matched_cells]),
                    bottom_right_y=max([c.bottom_right_y for c in matched_cells]),
                    bottom_right_x=max([c.bottom_right_x for c in matched_cells]),
                    row=min([c.row for c in matched_cells]),
                    col=min([c.col for c in matched_cells]),
                    row_span=max([c.row for c in matched_cells]) - min([c.row for c in matched_cells]) + 1,
                    col_span=max([c.col for c in matched_cells]) - min([c.col for c in matched_cells]) + 1,
                    text_boxes=cell.text_boxes,
                )
            )
        else:
            not_matched.append(cell)
    for _, g_cell in grid_cells_dict.items():
        linked_cells.append(
            CellLinked(
                top_left_y=g_cell.top_left_y,
                top_left_x=g_cell.top_left_x,
                bottom_right_y=g_cell.bottom_right_y,
                bottom_right_x=g_cell.bottom_right_x,
                row=g_cell.row,
                col=g_cell.col,
                row_span=1,
                col_span=1,
                text_boxes=[],
            )
        )
    if not grid_table.cols or not grid_table.rows or not grid_table.cells:
        return None, cells
    table = StructuredTable(
        bbox=BorderBox(
            top_left_y=grid_table.rows[0].top_left_y,
            top_left_x=grid_table.cols[0].top_left_x,
            bottom_right_y=grid_table.rows[-1].bottom_right_y,
            bottom_right_x=grid_table.cols[-1].bottom_right_x,
        ),
        cells=linked_cells,
    )
    return table, not_matched

def construct_table_from_cells(
    table_bbox: BorderBox, cells: List[Cell], image_shape: Tuple[int, int]
) -> Optional[StructuredTable]:
    if not table_bbox or not image_shape or not cells or len(cells) < 2:
        return None
    _ = _get_lines(cells, table_bbox)

    table_bbox.bottom_right_x = table_bbox.bottom_right_x + 2
    table_bbox.bottom_right_y = table_bbox.bottom_right_y + 2
    table_bbox.top_left_x = table_bbox.top_left_x - 2
    table_bbox.top_left_y = table_bbox.top_left_y - 2

    h_lines, v_lines = _find_lines(table_bbox, cells, image_shape)
    if not h_lines:
        h_lines = [table_bbox.top_left_y, table_bbox.bottom_right_y]
    elif len(h_lines) == 1:
        h_lines = (
            [table_bbox.top_left_y] + h_lines + [table_bbox.bottom_right_y]
        )
    if not v_lines:
        v_lines = [table_bbox.top_left_x, table_bbox.bottom_right_x]
    elif len(v_lines) == 1:
        v_lines = (
            [table_bbox.top_left_x] + v_lines + [table_bbox.bottom_right_x]
        )

    grid_table = find_grid_table(h_lines, v_lines)

    while True:
        _match_cells_and_table(grid_table, cells)
        vv_lines, hh_lines = _actualize_line_separators(
            grid_table, image_shape
        )
        if not vv_lines and not hh_lines:
            break
        h_lines.extend(hh_lines)
        v_lines.extend(vv_lines)
        grid_table = find_grid_table(sorted(h_lines), sorted(v_lines))

    table, _ = reconstruct_table_from_grid(grid_table, cells)
    if _:
        LOGGER.debug(f"Not matched: {len(_)}")
    return table

def cluster(coords: List[MutableParameter], eps=3, min_samples=1):
    if len(coords) < 3:
        return coords
    values = [coord.param for coord in coords]
    np_coords = np.array(values).reshape(-1, 1)
    clust = DBSCAN(eps=eps, min_samples=min_samples).fit(np_coords)
    lines = {}
    for coord, label in zip(coords, clust.labels_):
        if label in lines:
            lines[label].append(coord)
        else:
            lines[label] = [coord]
    lines_p = []
    for l_coords in lines.values():
        avg = int(sum([coord.param for coord in l_coords]) / len(l_coords))
        lines_p.append(avg)
        for coord in l_coords:
            coord.param = avg
    return lines_p

def to_mutable(bbox: BorderBox):
    return MutableBox(
        orig=bbox,
        top_left_x=MutableParameter(bbox.top_left_x),
        top_left_y=MutableParameter(bbox.top_left_y),
        bottom_right_x=MutableParameter(bbox.bottom_right_x),
        bottom_right_y=MutableParameter(bbox.bottom_right_y)
    )

def update_coords(bbox: MutableBox):
    bbox.orig.top_left_x = bbox.top_left_x.param + 1
    bbox.orig.top_left_y = bbox.top_left_y.param + 1
    bbox.orig.bottom_right_x = bbox.bottom_right_x.param - 1
    bbox.orig.bottom_right_y = bbox.bottom_right_y.param - 1

def _get_lines(cells: List[Cell], table_bbox: BorderBox):
    table_bbox_m = to_mutable(table_bbox)
    cells_m = [to_mutable(cell) for cell in cells]

    h_coords = [table_bbox_m.top_left_y, table_bbox_m.bottom_right_y]
    v_coords = [table_bbox_m.top_left_x, table_bbox_m.bottom_right_x]
    for cell in cells_m:
        v_coords.extend([cell.top_left_x, cell.bottom_right_x])
        h_coords.extend([cell.top_left_y, cell.bottom_right_y])

    v_l = cluster(v_coords)
    h_l = cluster(h_coords)

    update_coords(table_bbox_m)
    for cell in cells_m:
        update_coords(cell)

    return v_l, h_l


# -*- coding: utf-8 -*-
import os, sys
import time
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))

def erroDispositivo(dispositivo, comando):
    dataSave = dispositivo + " " + comando + " " + str(time.strftime("%d/%m/%Y %H:%M:%S")+"\n")
    try:
        data = ''
        with open('./LOG/logMqtt.txt', "r") as f:
            data = f.read()

        with open('./LOG/logMqtt.txt', "w") as f:
            f.write(dataSave+data)

    except FileNotFoundError:
         if os.path.exists('./LOG') == False:
              os.mkdir('./LOG')

         with open('./LOG/logMqtt.txt', "w") as f:
             f.write(dataSave)

def writeArquivo(dados, pasta, arquivo):
    dataSave = dados
    try:
        with open('./'+str(pasta)+'/'+str(arquivo), "w") as f:
            f.write(dataSave)

    except FileNotFoundError:
        if os.path.exists('./'+str(pasta)) == False:
            os.makedirs('./'+str(pasta))

        with open('./'+str(pasta)+'/'+str(arquivo), "w") as f:
            f.write(dataSave)

def readArquivo(pasta, arquivo):
    try:
        with open('./'+str(pasta)+'/'+str(arquivo), "r") as f:
            return f.read()

    except FileNotFoundError:
            print("erro saveFile.readArquivo")

def resultadoTeste(str):
    dataSave = str
    try:
        data = ""
        with open('./LOG/teste_estanqueidade.txt', "r") as f:
            data = f.read()
        with open('./LOG/teste_estanqueidade.txt', "w") as f:
            f.write(dataSave+data)

    except FileNotFoundError:
        if os.path.exists('./LOG') == False:
            os.mkdir('./LOG')

        with open('./LOG/teste_estanqueidade.txt', "w") as f:
            f.write(dataSave)

def resultadoTroca(str):
    dataSave = str
    try:
        data = ""
        with open('./LOG/troca_gasosa.txt', "r") as f:
            data = f.read()
        with open('./LOG/troca_gasosa.txt', "w") as f:
            f.write(dataSave+data)

    except FileNotFoundError:
        if os.path.exists('./LOG') == False:
            os.mkdir('./LOG')

        with open('./LOG/troca_gasosa.txt', "w") as f:
            f.write(dataSave)


import threading
from collections import deque
import time

class BusyWaitingThread(threading.Thread):
	def __init__(self):
		self._running = False
		self._tasks = deque([])
		threading.Thread.__init__(self)

	def run(self):
		self._running = True
		while self._running:
			if len(self._tasks) == 0:
				time.sleep(0.001)
				continue
			taskFn, afterTime = self._tasks[0]
			if time.time() > afterTime:
				# print("busyWaitingThread timeDiff (ms)", (time.time() - afterTime) * 1000)
				taskFn()
				self._tasks.popleft()

	def doTaskAfter(self, taskFn, afterTime):
		# Assume afterTime is always later than all existing tasks.
		self._tasks.append((taskFn, afterTime))

	def stop(self):
		self._running = False


import random
import re

class WSAT:
    def __init__(self):
        self.output = "NO"

    # This is the main function that performs the WalkSAT algorithm
    def infer(self, kb, query,test=False):
        maxIteration =400
        if test: #when using for unit test
            maxIteration = 600
        else:
            maxIteration = int(input("Enter the max iteration"))

        relevanceCount = self.relevanceCount(kb.sentences)

        # Create a random model using the symbols in the knowledge base
        randomModel = self.randomModel(kb.symbols)

        flipChance = 0.5

        for i in range(maxIteration):
            # If the random model satisfies all sentences in the knowledge base
            if (kb.PLTrue(randomModel)):
                    query.setValue(randomModel)
                    if query.result():
                        self.output = "YES "+ str(i)
                        return
                    else:
                        self.output = "NO"
                        return

            # Get a sentence from the knowledge base that is not satisfied by the random model
            randomSentence = self.getRandomFalseSentence(randomModel, kb.sentences)
            if randomSentence != None:
                # Flip a symbol in the random model with a chance of flipChance
                if (random.random() > flipChance):
                    self.flipRandomSymbol(randomSentence, randomModel)
                # Or flip the most relevant symbol
                else:
                    self.flipSymbolByRelevance(randomSentence, randomModel, relevanceCount)
            else:
                # If all sentences are satisfied, generate a new random model
                randomModel = self.randomModel(randomModel)

    def randomModel(self, kbSymbols):
        symbolList = {}

        # Go through each symbol and flip the symbol
        for symbol in kbSymbols.keys():
            symbolList[symbol] = random.choice([True, False])
        return symbolList

    def relevanceCount(self, sentenceList):
        relevanceCount = {}
        for sentence in sentenceList:
            # Find sentence that are not known facts
            if (len(sentence.lst) > 1):
                for symbol in range(len(sentence.lst)):
                    currentSymbol = sentence.lst[symbol]
                    if re.search("[a-zA-Z0-9]+", currentSymbol) != None:
                        # set the relance count for the symbol
                        if currentSymbol in relevanceCount:
                            relevanceCount[currentSymbol]+=1
                        else:
                            relevanceCount[currentSymbol] = 1
        return relevanceCount

    def getRandomFalseSentence(self, randomModel, sentenceList):
        hasFalseClause = False
        # Check if Knowledge base contain false clauses
        for sentence in sentenceList:
            sentence.setValue(randomModel)
            if sentence.result() == False:
                hasFalseClause = True
                break
        # Return none if there is no false clause in the knowledge base
        if hasFalseClause == False:
            return None

        # Get a random false clause from the knowledge base
        while True:
            randomIndex =random.randint(0, len(sentenceList)-1)
            sentenceList[randomIndex].setValue(randomModel)
            if sentenceList[randomIndex].result() == False:
                return sentenceList[randomIndex]

    def flipRandomSymbol(self, sentence, randomModel):
        while True:
            # Get a random index
            randomIndex = random.randint(0,len(sentence.lst)-1)
            if re.search("[a-zA-Z0-9]+", sentence.lst[randomIndex]) != None:
                # Flip the symbol in that index
                randomModel[sentence.lst[randomIndex]] = not randomModel[sentence.lst[randomIndex]]
                break

    def flipSymbolByRelevance(self, sentence, randomModel, relevanceCount):
        symbolToFlip = None

        for symbol in sentence.lst:
            if re.search("[a-zA-Z0-9]+", symbol) != None:
                # if the symbol to flip is none or the relance of teh symbol is higher than the current symbol to flip
                if symbolToFlip == None or relevanceCount[symbol] > relevanceCount[symbolToFlip]:
                    symbolToFlip = symbol

        if symbolToFlip != None:
            randomModel[symbolToFlip] = not randomModel[symbolToFlip]


"""
  Name     : c12_36_terminal_stock_price_distribution.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""
import scipy as sp
import matplotlib.pyplot as plt
from scipy import zeros, sqrt, shape
#input area
S0 = 9.15               # stock price at time zero
T =1.                   # years
n_steps=100.            # number of steps
mu =0.15                # expected annual return
sigma = 0.2             # volatility (annual)
sp.random.seed(12345)   # fix those random numbers
n_simulation = 1000     # number of simulation
dt =T/n_steps
#
S = zeros([n_simulation], dtype=float)
x = range(0, int(n_steps), 1)
for j in range(0, n_simulation):
    tt=S0
    for i in x[:-1]:
        e=sp.random.normal()
        tt+=tt*(mu-0.5*pow(sigma,2))*dt+sigma*tt*sqrt(dt)*e;
        S[j]=tt
#
plt.title('Histogram of terminal price')
plt.ylabel('Number of frequencies')
plt.xlabel('Terminal price')
plt.figtext(0.5,0.8,'S0='+str(S0)+',mu='+str(mu)+',sigma='+str(sigma))
plt.figtext(0.5,0.76,'T='+str(T)+', steps='+str(int(n_steps)))
plt.figtext(0.5,0.72,'Number of terminal prices='+str(int(n_simulation)))
plt.hist(S)
plt.show()


"""
********* Euler Problem 17 *********
PROMPT:
If the numbers 1 to 5 are written out in words:
one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.

If all the numbers from 1 to 1000 (one thousand) inclusive were written out in
words, how many letters would be used?

NOTE: Do not count spaces or hyphens.
For example, 342 (three hundred and forty-two) contains 23 letters and
115 (one hundred and fifteen) contains 20 letters.
The use of "and" when writing out numbers is in compliance with British usage.

"""

# Create function that maps an integer to its number of letters
# using a dictionary.
def numtostr(x, n):
    if n == 1:  # 1-19
        switcher = {
            0: 0,
            1: 3,
            2: 3,
            3: 5,
            4: 4,
            5: 4,
            6: 3,
            7: 5,
            8: 5,
            9: 4,
            10: 3,
            11: 6,
            12: 6,
            13: 8,
            14: 8,
            15: 7,
            16: 7,
            17: 9,
            18: 8,
            19: 8
        }
        return switcher.get(x, "not a number bruv")
    else: # number of letters for "twenty", "thirty", etc.
        switcher = {
            2: 6,
            3: 6,
            4: 5,
            5: 5,
            6: 5,
            7: 7,
            8: 6,
            9: 6
        }
        return switcher.get(int(str(x)[0]), "not a number bruv")

# Loop through each number and use numtostr
total = 0
for i in range(1,1000):
    # 1-20 are unique numbers
    if i < 20:
        num = numtostr(i, 1)
    # 21 - 99 use a prefix such as ninety, then a 1-9 # following it
    elif i < 100:
        num = numtostr(i, 2)+numtostr(int(str(i)[1]), 1)
    # 100-999 contains a "x" hundred, with a potential "and"
    else:
        # trail = the last two digits of the number
        trail = int(str(i)[1:])
        # Calculate an interim number for the trail using identical process
        # as above (1-20 vs 21-99)
        if trail < 20:
            inum = numtostr(trail, 1)
        else:
            inum = numtostr(trail, 2)+numtostr(int(str(trail)[1]), 1)
        # if trail = 0, it means it is a multiple of 100
        # multiples of 100 will not have an "and". "hundred" is 7 letters
        if trail == 0:
            prep = 7
        else:
            prep = 10
        # sum up the first digit numtostr with prep and the trail numtostr
        num = numtostr(int(str(i)[0]), 1) + prep + inum
    total += num
total += 11 # one thousand = 11 letters

print(total)


from datetime import datetime

from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy_utils import EmailType, generic_repr

from ...application import db

db.JSONB, db.UUID, db.EmailType = (JSONB, UUID, EmailType)

@generic_repr
class Base(db.Model):
    __abstract__ = True
    created_on = db.Column(
        db.DateTime, default=datetime.utcnow, server_default=db.func.now()
    )
    updated_on = db.Column(
        db.DateTime,
        default=datetime.utcnow,
        onupdate=datetime.utcnow,
        server_default=db.func.now(),
    )
    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)


import socket

HOST = '43.207.32.202'
PORT = 65432

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
d = s.recv(1024)
s.sendall(b'Logs,Data')
print('Sending request for Logs Data')
data = s.recv(2048)
print('Received Data:', data)


from django.urls import path
from rest_framework_nested import routers
from . import views
from core.views import (
    ApartmentImageViewSet,
    ContractViewSet,
    BillViewSet,
    RoomImageViewSet,
    RoomViewSet,
)

app_name = "owner"

router = routers.DefaultRouter()
router.register("owner-apartments", views.OwnerApartmentViewSet, basename="apartments")
router.register("owner-rooms", views.OwnerRoomViewSet, basename="rooms")
router.register("owner-contarcts", ContractViewSet, basename="contracts")
router.register("owner-bills", BillViewSet, basename="bills")

urlpatterns = [
    path(
        "owner-apartments/<int:pk>/upload_image/",
        views.OwnerApartmentViewSet.as_view({"patch": "upload_image"}),
        name="apartment-upload-image",
    ),
    path(
        "owner-apartments/<int:apartment_id>/rooms/",
        views.OwnerRoomViewSet.as_view(
            {
                "get": "list",
                "put": "update",
                "delete": "destroy",
                "post": "create",
                "patch": "partial_update",
            }
        ),
        name="rooms",
    ),
    path(
        "owner-apartments/<int:apartment_id>/rooms/",
        views.OwnerRoomViewSet.as_view(
            {
                "get": "list",
                "put": "update",
                "delete": "destroy",
                "post": "create",
                "patch": "partial_update",
            }
        ),
        name="owner-room-detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:pk>/",
        RoomViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "delete": "destroy",
                "post": "create_contract",
                "patch": "partial_update",
            }
        ),
        name="room-detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/contracts/<int:pk>/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="contract_detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:room_id>/contracts/",
        ContractViewSet.as_view(
            {
                "get": "list",
                "post": "create",
            }
        ),
        name="contracts",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:room_id>/contracts/<int:pk>/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="contract_detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:pk>/",
        BillViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="bill_detail",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:pk>/upload_file/",
        BillViewSet.as_view(
            {
                "patch": "upload_file",
                "post": "upload_fle",
            }
        ),
        name="bill-upload-file",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:bill_id>/download/",
        BillViewSet.as_view({"get": "download"}),
        name="bill-download-file",
    ),
    path(
        "owner-rooms/<int:room_id>/contracts/<int:pk>/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="contract_detail",
    ),
    path(
        "owner-rooms/<int:pk>/create_contract/",
        ContractViewSet.as_view(
            {
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
                "post": "create",
            }
        ),
        name="create_contract",
    ),
    path(
        "owner-apartments/<int:apartment_id>/bills/<int:pk>/delete-file/",
        BillViewSet.as_view({"delete": "delete_file"}),
        name="delete_bill_file",
    ),
    path(
        "owner-apartments/<int:apartment_id>/room/<int:room_id>/contracts/<int:pk>/delete-file/",
        ContractViewSet.as_view({"delete": "delete_file"}),
        name="delete_contract_file",
    ),
    path(
        "owner-apartments/<int:apartment_id>/images/",
        ApartmentImageViewSet.as_view({"get": "list"}),
        name="apartment_image_list",
    ),
    path(
        "owner-apartments/<int:apartment_id>/images/<int:pk>/",
        ApartmentImageViewSet.as_view({"get": "retrieve", "delete": "destroy"}),
        name="apartment_image_detail",
    ),
    path(
        "owner-rooms/<int:room_id>/images/",
        RoomImageViewSet.as_view({"get": "list"}),
        name="room_image_list",
    ),
    path(
        "owner-rooms/<int:room_id>/images/<int:pk>/",
        RoomImageViewSet.as_view({"get": "retrieve", "delete": "destroy"}),
        name="room_image_detail",
    ),
] + router.urls


# eng_network_single_b29.py
# Version b29
# by jmg - j.gagen*AT*gold*DOT*ac*DOT*uk
# May 10th 2016

# Licence: http://creativecommons.org/licenses/by-nc-sa/3.0/
# Source code at: https://github.com/pha5echange/eng-tools

# Name changed to 'eng_network_single'

# Plots network graph from edgelist 'data\OMEGAYEAR_wuGraphData.txt'
# Adds dates from 'data\first_clusters.txt' as node attributes
# Adds artist numbers from 'data\OMEGAYEAR_artistNums.txt' as node attributes
# Removes nodes where date-cluster information is not available
# Removes self-loop edges and zero-degree nodes if required
# Removes nodes based upon 'incepDate' if required - all nodes NEWER than Omega Year are removed
# Displays using parameters from 'config/config_nw.txt'
# Writes 'data\eng_network_wd_nodeList.txt' with nodes and degrees (k), '...edgeList.txt' with neighbours
# Writes analysis files to 'results\'
# Writes gexf files to 'gexf\', including 'gexf\YEAR.gexf' for use by 'nhm.py'
# Writes image to 'networks\'
# This version incorporates PageRank
# Incorporates Artist Time Slicing
# Added 'maxDeg' metric and 'isolated nodes' counter
# This version writes a list of nodes in the Largest Connected Component to 'ts_data' and a GEXF of the LCC

# Run AFTER 'eng_nodesets.py'

# Import packages
import os
import resource
import numpy as np
import networkx as nx
import community
from networkx.algorithms.approximation import clique
import matplotlib.pyplot as plt
from collections import OrderedDict
from datetime import datetime

versionNumber = ("b29")

# Initiate timing of run
runDate = datetime.now()
startTime = datetime.now()

# Create 'logs' subdirectory if necessary
if not os.path.exists("logs"):
    os.makedirs("logs")

# Create 'data' subdirectories if necessary
if not os.path.exists("data"):
	os.makedirs("data")

if not os.path.exists("data/node-edge-lists"):
	os.makedirs("data/node-edge-lists")

# Create 'gexf' subdirectories if necessary
if not os.path.exists("gexf"):
	os.makedirs("gexf")

if not os.path.exists("gexf/initial"):
	os.makedirs("gexf/initial")

if not os.path.exists("gexf/directed"):
	os.makedirs("gexf/directed")

if not os.path.exists("gexf/final"):
	os.makedirs("gexf/final")

if not os.path.exists("gexf/lcc"):
	os.makedirs("gexf/lcc")

# Create 'results' subdirectories if necessary
if not os.path.exists("results"):
	os.makedirs("results")

if not os.path.exists("results/analysis"):
	os.makedirs("results/analysis")

# Create 'networks' subdirectory if necessary
if not os.path.exists("networks"):
    os.makedirs("networks")

# Open file for writing log
logPath = os.path.join("logs", 'eng_network_single_' + versionNumber + '_log.txt')
runLog = open(logPath, 'a')

# Begin
print ('\n' + "Single-Network Thing | Version " + versionNumber + " | Starting...")
runLog.write ("==========================================================================" + '\n' + '\n')
runLog.write ("Single-Network Thing | Version " + versionNumber + '\n' + '\n')

# Get user input
print
dateIP = int(input ("Enter an omega year for this graph (or 0 to leave the network intact): "))
omegaYear = str(dateIP)

# Uncomment the line below to facilitate optional self-loop removal
#selfLoopIP = int(input ("Enter 1 here to remove self-loop edges: "))
# Auto-remove self-loops - comment out the line below if self-loop removal is optional
selfLoopIP = 1

# Uncomment the line below to facilitate optional isolate removal
#isolatedIP = int(input ("Enter 1 here to remove isolated nodes: "))
# Do not remove isolated nodes - comment out the line below if isolate removal is optional
isolatedIP = 0

# Generate dictionary containing nodenames and dates (from 'data\first_cluster.txt')
dateInputPath = os.path.join("data", 'first_cluster.txt')
dateInput = open(dateInputPath, 'r')

dateDict = {}

for line in dateInput:
	genreInput, genreDate, newline = line.split(",")

	# Remove genres AFTER the Omega Year
	intGenreDate = int(genreDate)

	if intGenreDate <= dateIP:
		genreName = str(omegaYear + '_' + genreInput).replace(" ", "")
		dateDict[genreName] = genreDate

sortDates = OrderedDict(sorted(dateDict.items()))

# Generate dictionary containing nodenames and artist numbers (from 'data\OMEGAYEAR\_artistNums.txt')
artistInputPath = os.path.join("ts_data", omegaYear, omegaYear + '_artistNums.txt')
artistInput = open(artistInputPath, 'r').readlines()

firstLine = artistInput.pop(0)

artistDict = {}

for line in artistInput:
	genreInput, artistNum, newline = line.split(",")
	genreName = str(genreInput).replace(" ", "")
	artistDict[genreName] = artistNum

sortArtists = OrderedDict(sorted(artistDict.items()))

# Open file to write list of nodes
nodeListPath = os.path.join("ts_data", omegaYear, 'eng_network_' + versionNumber + '_' + omegaYear + '_nodeList.txt')
nodeListOP = open (nodeListPath, 'w')

# Open file for writing LCC nodes
lccPath = os.path.join("ts_data", omegaYear, 'eng_network_' + versionNumber + '_' + omegaYear + '_lcc.txt')
lccOP = open(lccPath, 'w')

# Open file to write list of edges
edgeListPath = os.path.join("ts_data", omegaYear, 'eng_network_' + versionNumber + '_' + omegaYear + '_edgeList.txt')
edgeListOP = open (edgeListPath, 'w')

# Open file for writing initial gexf
gexfPath = os.path.join("gexf/initial", 'eng_network_' + versionNumber + '_' + omegaYear + '.gexf')
gexfFile = open(gexfPath, 'w')

# Open file for writing digraph gexf
gexfDPath = os.path.join("gexf/directed", omegaYear + '.gexf')
gexfDFile = open(gexfDPath, 'w')

# Open file for writing final gexf
gexfFinPath = os.path.join("gexf/final", 'eng_network_final_' + versionNumber + '_' + omegaYear + '.gexf')
gexfFinFile = open(gexfFinPath, 'w')

# OPen file for writing LCC gexf
gexfLccPath = os.path.join("gexf/lcc", 'eng_lcc_' + versionNumber + '_' + omegaYear + '.gexf')
gexfLccFile = open(gexfLccPath, 'w')

# Open file for Page Rank data
prPath = os.path.join("ts_data", omegaYear, omegaYear +'_pagerank.txt')
prFile = open(prPath, 'w')

# Open file for analysis results
anPath = os.path.join("results/analysis", 'eng_network_' + versionNumber + '_' + omegaYear + '_analysis.txt')
anFile = open(anPath, 'w')

# Open file to write image
nwImgPath = os.path.join("networks", 'eng_network_' + versionNumber + '_' + omegaYear + '_nw.eps')

anFile.write ('\n' + "==========================================================================" + '\n' + '\n')
anFile.write ("Single-Network Thing | Version " + versionNumber + '\n' + '\n')

# Read the edgelist and generate undirected graph
print ('\n' + "Importing Weighted Edge List... ")
inputPath = os.path.join("ts_data", omegaYear, omegaYear + '_wuGraph_data.txt')
edgeList = open (inputPath, 'r')
enGraph = nx.read_weighted_edgelist(edgeList, delimiter=',')

# Calculate basic graph statistics
print ('\n' + "Calculating various things... " + '\n')
nodes = nx.number_of_nodes(enGraph)
edges = nx.number_of_edges(enGraph)
density = nx.density(enGraph)
nodeList = nx.nodes(enGraph)
nodeList.sort()
selfLoopTotal = enGraph.number_of_selfloops()
#selfLoops = enGraph.selfloop_edges()
connections = edges - selfLoopTotal

print ('Nodes: ' + str(nodes))
print ('Edges: ' + str(edges))
print ('Number of self-loops: ' + str(selfLoopTotal))
#print ('Self-loop edges: ' + str(selfLoops))
print ('Connections (edges minus self-loops): ' + str(connections))
print ('Density: ' + str(density))
print

runLog.write ('Initial data: ' + '\n' + '\n')
runLog.write ('User-entered date: ' + str(dateIP) + '\n')
runLog.write ('Nodes: ' + str(nodes) + '\n')
runLog.write ('Edges: ' + str(edges) + '\n')
runLog.write ('Self-loops: ' + str(selfLoopTotal) + '\n')
#runLog.write ('Self-loop edges: ' + str(selfLoops) + '\n')
runLog.write ('Connections (edges minus self-loops): ' + str(connections) + '\n')
runLog.write ('Density: ' + str(density) + '\n')

# Apply artist numbers of nodes as attributes
print ('Applying total artist number attribute to nodes...' + '\n')
runLog.write ('\n' + 'Applying total artist number attribute to nodes...' + '\n')
nx.set_node_attributes (enGraph, 'totalArtists', sortArtists)

# Discard nodes without first-cluster dates
noDateNode = 0
print ('Checking genre inception dates, and removing if none...' + '\n')
for i in nodeList:
	if not i in sortDates.keys():
		enGraph.remove_node(i)
		print ('Removed node ' + str(i))
		noDateNode += 1

if noDateNode == 1:
	print ('\n' + 'Removed ' + str(noDateNode) + ' node due to no inception date.')
	runLog.write ('\n' + 'Removed ' + str(noDateNode) + ' node due to no inception date.' + '\n')

if noDateNode > 1:
	print ('\n' + 'Removed ' + str(noDateNode) + ' nodes due to no inception dates.')
	runLog.write ('\n' + 'Removed ' + str(noDateNode) + ' nodes due to no inception dates.' + '\n')

# Apply dates of nodes as attributes
print ('Applying inception date attribute to nodes...' + '\n')
runLog.write ('\n' + 'Applying inception date attribute to nodes...' + '\n')
nx.set_node_attributes (enGraph, 'incepDate', sortDates)

# Recalculate basic graph statistics
print ('\n' + 'Recalculating various things...' + '\n')
nodes = nx.number_of_nodes(enGraph)
edges = nx.number_of_edges(enGraph)
density = nx.density(enGraph)
nodeList = nx.nodes(enGraph)
nodeList.sort()
selfLoopTotal = enGraph.number_of_selfloops()
connections = edges - selfLoopTotal

print ('Nodes: ' + str(nodes))
print ('Edges: ' + str(edges))
print ('Self-loops: ' + str(selfLoopTotal))
print ('Connections (edges minus self-loops): ' + str(connections))
print ('Density: ' + str(density))
print

runLog.write ('\n' + 'Stage 1 data: ' + '\n' + '\n')
runLog.write ('Nodes: ' + str(nodes) + '\n')
runLog.write ('Edges: ' + str(edges) + '\n')
runLog.write ('Self-loops: ' + str(selfLoopTotal) + '\n')
runLog.write ('Connections (edges minus self-loops): ' + str(connections) + '\n')
runLog.write ('Density: ' + str(density) + '\n')

# Remove nodes where 'incepDate' attribute is NEWER than user input ('dateIP')
if dateIP != 0:
	runLog.write('\n' + 'Removing nodes based upon user date input...' + '\n')
	for i in nodeList:
		incepDate = nx.get_node_attributes (enGraph, 'incepDate')
		intIncep = int(incepDate[i])
		if intIncep > dateIP:
			enGraph.remove_node(i)
			print ('Removed newer node ' + str(i) + ' based upon user date input.')
else:
	print ('No nodes removed based upon user date input.')
	runLog.write ('\n' + 'No nodes removed based upon user date input.' + '\n')

# Recalculate basic graph statistics
print ('\n' + 'Recalculating various things...' + '\n')
nodes = nx.number_of_nodes(enGraph)
edges = nx.number_of_edges(enGraph)
density = nx.density(enGraph)
nodeList = nx.nodes(enGraph)
nodeList.sort()
selfLoopTotal = enGraph.number_of_selfloops()
connections = edges - selfLoopTotal

print ('Nodes: ' + str(nodes))
print ('Edges: ' + str(edges))
print ('Self-loops: ' + str(selfLoopTotal))
print ('Connections (edges minus self-loops): ' + str(connections))
print ('Density: ' + str(density))
print

runLog.write ('\n' + 'Stage 2 data: ' + '\n' + '\n')
runLog.write ('Nodes: ' + str(nodes) + '\n')
runLog.write ('Edges: ' + str(edges) + '\n')
runLog.write ('Self-loops: ' + str(selfLoopTotal) + '\n')
runLog.write ('Connections (edges minus self-loops): ' + str(connections) + '\n')
runLog.write ('Density: ' + str(density) + '\n')

# Remove self-loops
selfLoopCount = 0
if selfLoopIP == 1:
	print ('\n' + 'Checking for and removing self-loops...' + '\n')
	runLog.write('\n' + 'Checking for and removing self-loops...' + '\n')
	for u,v,data in enGraph.edges(data=True):
		if u == v:
			enGraph.remove_edge(u,v)
			print ('removed self-loop ' + str(u))
			selfLoopCount += 1

	if selfLoopCount == 1:
		print ('\n' + 'Removed ' + str(selfLoopCount) + ' self-loop edge.')
		runLog.write ('\n' + 'Removed ' + str(selfLoopCount) + ' self-loop edge.' + '\n')

	if selfLoopCount > 1:
		print ('\n' + 'Removed ' + str(selfLoopCount) + ' self-loop edges.')
		runLog.write ('\n' + 'Removed ' + str(selfLoopCount) + ' self-loop edges.' + '\n')
else:
	print ('Self-loops intact.' + '\n')
	runLog.write('\n' + 'Self-loops intact.' + '\n')

# Remove zero degree nodes
isolateCount = 0
if isolatedIP == 1:

	print ('\n' + 'Checking for and removing isolated (zero degree) nodes...' +'\n')
	runLog.write('\n' + 'Checking for and removing isolated (zero degree) nodes...' +'\n' + '\n')
	for i in nodeList:
		if nx.is_isolate(enGraph,i):
			enGraph.remove_node(i)
			print ('Removed isolated node ' + str(i))
			runLog.write('Removed isolated node ' + str(i) + '\n')
			isolateCount += 1

	if isolateCount == 1:
		print ('\n' + "Removed " + str(isolateCount) + " isolated node. " + '\n')
		runLog.write ('\n' + "Removed " + str(isolateCount) + " isolated node. " + '\n')

	if isolateCount > 1:
		print ('\n' + "Removed " + str(isolateCount) + " isolated nodes. " + '\n')
		runLog.write ('\n' + "Removed " + str(isolateCount) + " isolated nodes. " + '\n')

else:

	for i in nodeList:
		if nx.is_isolate(enGraph,i):
			isolateCount += 1

	if isolateCount == 1:
		print ('\n' + str(isolateCount) + ' isolated node intact.')
		runLog.write('\n' + str(isolateCount) + ' isolated node intact.' + '\n')

	if isolateCount > 1:
		print ('\n' + str(isolateCount) + ' isolated nodes intact.')
		runLog.write('\n' + str(isolateCount) + ' isolated nodes intact.' + '\n')

# Recalculate basic graph statistics
print ('Recalculating various things...' + '\n')
nodes = nx.number_of_nodes(enGraph)
edges = nx.number_of_edges(enGraph)
density = nx.density(enGraph)
nodeList = nx.nodes(enGraph)
nodeList.sort()
selfLoopTotal = enGraph.number_of_selfloops()

print ('Nodes: ' + str(nodes))
print ('Isolated nodes:' + str(isolateCount))
print ('Edges: ' + str(edges))
print ('Self-loops: ' + str(selfLoopTotal))
print ('Density: ' + str(density))
print

runLog.write ('\n' + 'Stage 3 data: ' + '\n' + '\n')
runLog.write ('Nodes: ' + str(nodes) + '\n')
runLog.write ('Isolated nodes:' + str(isolateCount) + '\n')
runLog.write ('Edges: ' + str(edges) + '\n')
runLog.write ('Self-loops: ' + str(selfLoopTotal) + '\n')
runLog.write ('Density: ' + str(density) + '\n')

# Clean edge-labels
print ('Cleaning edge labels...')
labels = {}
for u,v,data in enGraph.edges(data=True):
	labels[(u,v)] = int(data['weight'])

# Write file with nodes and degree,for reference
print ('\n' + 'Writing node list with degree and neighbours...' + '\n')
for i in nodeList:
	nodeDegree = enGraph.degree(i)
	neighboursList = list(nx.all_neighbors(enGraph, i))
	nodeListOP.write(str(i) + ',' + str(nodeDegree) + ',' + str(neighboursList) +'\n')
	print ("Node " + str(i) + " degree: " + str(nodeDegree))
	print ("Neighbours: " + str(neighboursList))

nodeListOP.close()

# Calculate new graph-wide total artists value
# Use artist-total node attributes
totalArtists = 0
totalEdgeWeight = 0
edgeList = enGraph.edges(data=True)

for i in nodeList:
	nodeArtists = int(sortArtists[i])
	totalArtists += nodeArtists

for i in edgeList:
	nodesStr = str(i).replace("u'","").replace("'","").replace("(","").replace(")","").replace(" ","")
	nodeU, nodeV, edgeData = nodesStr.split(",")
	edgeWeight = float(str(edgeData).replace("{weight:","").replace("}",""))
	totalEdgeWeight += edgeWeight

# Analysis
print ('\n' + 'Analysing undirected graph...' + '\n')
print ('Average clustering coefficient...' + '\n')
avClustering = nx.average_clustering(enGraph)
print ('Connected components...' + '\n')
connectComp = [len(c) for c in sorted(nx.connected_components(enGraph), key=len, reverse=True)]
print ('Find cliques...' + '\n')
cl = nx.find_cliques(enGraph)
cl = sorted(list(cl), key = len, reverse = True)
print ('Number of cliques: ' + str(len(cl)) + '\n')
cl_sizes = [len(c) for c in cl]
#print ('Size of cliques: ' + str(cl_sizes))

print ('\n' + 'Undirected graph data: ' + '\n')
print ('Nodes: ' + str(nodes))
print ('Edges: ' + str(edges))
print ('Self-loops: ' + str(selfLoopTotal))
print ('Density: ' + str(density))
print ('Average Clustering Coefficient: ' + str(avClustering))
print ('Number of cliques: ' + str(len(cl)))
print ('Connected Components: ' + str(connectComp))
print
print (str(nx.info(enGraph)))
print

runLog.write ('\n' + 'Undirected graph data: ' + '\n' + '\n')
runLog.write ('Nodes: ' + str(nodes) + '\n')
runLog.write ('Edges: ' + str(edges) + '\n')
runLog.write ('Self-loops: ' + str(selfLoopTotal) + '\n')
runLog.write ('Density: ' + str(density) + '\n')
runLog.write ('Average Clustering Coefficient: ' + str(avClustering) + '\n')
runLog.write ('Number of cliques: ' + str(len(cl)) + '\n')
runLog.write ('Connected Components: ' + str(connectComp) + '\n')
runLog.write ('\n' + str(nx.info(enGraph)) + '\n')

# Write undirected gexf file for use in Gephi
print ("Writing undirected gexf file... " + '\n')
runLog.write('\n' + "Writing undirected gexf file... " + '\n')
nx.write_gexf(enGraph, gexfFile)
gexfFile.close()

# Direct graph and write gexf of this
print ("Directing graph... " + '\n')
runLog.write('\n' + "Directing graph..." + '\n')
diEnGraph = nx.DiGraph()
diEnGraph.add_nodes_from(enGraph.nodes(data=True))
diEnGraph.add_edges_from(enGraph.edges(data=True))

edgeList = diEnGraph.edges(data=True)
removedNodes = 0
for i in edgeList:
	# clean up fraking unicode string
	nodesStr = str(i).replace("u'","").replace("'","").replace("(","").replace(")","").replace(" ","")

	# display / write a list of edges
	print(nodesStr)
	edgeListOP.write(nodesStr + '\n')

	# implement calculation for edge-direction
	nodeU, nodeV, edgeData = nodesStr.split(",")
	edgeWeight = float(str(edgeData).replace("{weight:","").replace("}",""))
	nodeUdate = int(sortDates[nodeU])
	print(nodeUdate)
	nodeVdate = int(sortDates[nodeV])
	print (nodeVdate)

	if nodeUdate > nodeVdate:
		# direct from v to u
		print("Directing edge from V to U" + '\n')
		# remove the edge
		diEnGraph.remove_edge(nodeU,nodeV)
		# add a directed edge
		diEnGraph.add_edge(nodeV, nodeU, weight=edgeWeight)

	elif nodeVdate > nodeUdate:
		# direct from u to v
		print("Direct from U to V" + '\n')
		# remove the edge
		diEnGraph.remove_edge(nodeU,nodeV)
		# add a directed edge
		diEnGraph.add_edge(nodeU, nodeV,  weight=edgeWeight)

	elif nodeUdate == nodeVdate:
		# remove the edge
		diEnGraph.remove_edge(nodeU,nodeV)
		# write to a list of removed edges
		removedNodes += 1
		print("Removed edge between nodes " + str(nodeU) + " and " + str(nodeV) + " due to identical node inception dates. " + '\n')
		edgeListOP.write("Removed edge between nodes " + str(nodeU) + " and " + str(nodeV) + " due to identical node inception dates. " + '\n')

print (str(removedNodes) + " edges removed due to identical node inception dates. " + '\n')
runLog.write ('\n' + str(removedNodes) + " edges removed due to identical node inception dates. " + '\n')
edgeListOP.close()

print ("Writing directed gexf file... " + '\n')
runLog.write('\n' + "Writing directed gexf file... " + '\n')
nx.write_gexf(diEnGraph, gexfDFile)
gexfDFile.close()

# Recheck zero degree nodes
print ('Rechecking isolated (zero degree) nodes...' +'\n')
runLog.write('\n' + 'Rechecking isolated (zero degree) nodes...' +'\n' + '\n')

diNodeList = nx.nodes(diEnGraph)
diNodeList.sort()

isolateCount = 0
if isolatedIP == 1:

	for i in diNodeList:
		if nx.is_isolate(diEnGraph,i):
			diEnGraph.remove_node(i)
			print ('Removed isolated node ' + str(i))
			runLog.write('Removed isolated node ' + str(i) + '\n')
			isolateCount += 1

	if isolateCount == 1:
		print ("Removed " + str(isolateCount) + " isolated node. " + '\n')
		runLog.write ('\n' + "Removed " + str(isolateCount) + " isolated node. " + '\n')

	if isolateCount > 1:
		print ("Removed " + str(isolateCount) + " isolated nodes. " + '\n')
		runLog.write ('\n' + "Removed " + str(isolateCount) + " isolated nodes. " + '\n')

else:

	for i in diNodeList:
		if nx.is_isolate(diEnGraph,i):
			isolateCount += 1

	if isolateCount == 1:
		print (str(isolateCount) + ' isolated node intact.' +'\n')
		runLog.write('\n' + str(isolateCount) + ' isolated node intact.' + '\n')

	if isolateCount > 1:
		print (str(isolateCount) + ' isolated nodes intact.' + '\n')
		runLog.write('\n' + str(isolateCount) + ' isolated nodes intact.' + '\n')

# Plot and display graph
# Graph plotting parameters - moved to config file 'config_nw.txt'
print ('Reading layout config file...' + '\n')

# Open and read 'config_nw.txt'
nwConfigPath = os.path.join ("config", 'config_nw.txt')
nwConfig = open(nwConfigPath, 'r').readlines()

# Remove the first line
firstLine = nwConfig.pop(0)

for line in nwConfig:
	n_size, n_alpha, node_colour, n_text_size, text_font, e_thickness, e_alpha, edge_colour, l_pos, e_text_size, edge_label_colour = line.split(",")

node_size = int(n_size)
node_alpha = float(n_alpha)
node_text_size = int(n_text_size)
edge_thickness = int(e_thickness)
edge_alpha = float(e_alpha)
label_pos = float(l_pos)
edge_text_size = int(e_text_size)

print ('Laying out graph...' + '\n')

#nx.draw(enGraph)
graph_pos = nx.spring_layout(diEnGraph)
nx.draw_networkx_nodes(diEnGraph, graph_pos, node_size = node_size, alpha = node_alpha, node_color=node_colour)
nx.draw_networkx_edges(diEnGraph, graph_pos, width = edge_thickness, alpha = edge_alpha, color = edge_colour)
#nx.draw_networkx_labels(diEnGraph, graph_pos, font_size = node_text_size, font_family = text_font)
#nx.draw_networkx_edge_labels(diEnGraph, graph_pos, edge_labels = labels, label_pos = label_pos, font_color = edge_label_colour, font_size = edge_text_size, font_family = text_font)

# write image file
#print ('Writing image file...' + '\n')
plt.savefig(nwImgPath, format = 'eps', bbox_inches='tight')

# display graph
print ('Displaying graph...' + '\n')
plt.show()

# Clear plot
plt.clf()

# Recalculate basic graph statistics
nodes = nx.number_of_nodes(diEnGraph)
edges = nx.number_of_edges(diEnGraph)
nodeList = nx.nodes(diEnGraph)
nodeList.sort()
density = nx.density(diEnGraph)
isDag = nx.is_directed_acyclic_graph(diEnGraph)

# Count sources and sinks
sourceCount = 0
sinkCount = 0
for i in nodeList:
	outDeg = diEnGraph.out_degree(i)
	inDeg = diEnGraph.in_degree(i)
	if outDeg == 0 and inDeg >= 1:
		sinkCount += 1

	elif inDeg == 0 and outDeg >= 1:
		sourceCount += 1

print ('Final Directed Graph Information' + '\n')
print ('User-entered date: ' + str(dateIP))
print ('Nodes: ' + str(nodes))
print ('Isolated nodes: ' + str(isolateCount))
print ('Source nodes: ' + str(sourceCount))
print ('Sink nodes: ' + str(sinkCount))
print ('Edges: ' + str(edges))
print ('Density: ' + str(density))
print ('Is DAG? ' + str(isDag))
print
print (str(nx.info(diEnGraph)))

anFile.write ('Nodes: ' + str(nodes) + '\n')
anFile.write ('Isolated nodes: ' + str(isolateCount) + '\n')
anFile.write ('Source nodes: ' + str(sourceCount) + '\n')
anFile.write ('Sink nodes: ' + str(sinkCount) + '\n')
anFile.write ('Edges: ' + str(edges) + '\n')
anFile.write ('Density: ' + str(density) + '\n')
anFile.write ('Is DAG? ' + str(isDag) + '\n')
anFile.write ('\n' + str(nx.info(diEnGraph)) + '\n')

runLog.write ('\n' + 'Final Directed Graph Information' + '\n' + '\n')
runLog.write ('User-entered date: ' + str(dateIP) + '\n')
runLog.write ('Nodes: ' + str(nodes) + '\n')
runLog.write ('Isolated nodes:' + str(isolateCount) + '\n')
runLog.write ('Source nodes: ' + str(sourceCount) + '\n')
runLog.write ('Sink nodes: ' + str(sinkCount) + '\n')
runLog.write ('Edges: ' + str(edges) + '\n')
runLog.write ('Density: ' + str(density) + '\n')
runLog.write ('Is DAG? ' + str(isDag) + '\n')
runLog.write ('\n' + str(nx.info(diEnGraph)) + '\n')

prFile.write(str(nx.pagerank(diEnGraph)))
prFile.close()

# Render undirected version of diEnGraph to facilitate final analysis of graph characteristics
print('\n' + "Rendering undirected version to facilitate final analysis of graph characteristics... ")
runLog.write('\n' + "Rendering undirected version to facilitate final analysis of graph characteristics... " + '\n')
newEnGraph = diEnGraph.to_undirected()

# Analysis
print ('\n' + 'Analysing final undirected graph...' + '\n')
print ('Maximal degree... ' + '\n')
degreeSeq = sorted(nx.degree(newEnGraph).values(),reverse=True)
maxDeg = max(degreeSeq)
print ('Maximal degree: ' + str(maxDeg) + '\n')
anFile.write ('Maximal degree: ' + str(maxDeg) + '\n')
print ('Average clustering coefficient...' + '\n')
avClustering = nx.average_clustering(newEnGraph)
print ('Connected components...' + '\n')
connectComp = [len(c) for c in sorted(nx.connected_components(newEnGraph), key=len, reverse=True)]
print ('Find cliques...' + '\n')
cl = nx.find_cliques(newEnGraph)
cl = sorted(list(cl), key = len, reverse = True)
print ('Number of cliques: ' + str(len(cl)) + '\n')
anFile.write ('Number of cliques: ' + str(len(cl)) + '\n')
cl_sizes = [len(c) for c in cl]
#print ('Size of cliques: ' + str(cl_sizes))
anFile.write ('Size of cliques: ' + str(cl_sizes) + '\n' + '\n')

# Find LCC nodes, print to screen and and write to file
largeCC = max(nx.connected_components(newEnGraph), key=len)
print
print ("Nodes in LCC: ")
print
print (largeCC)
lccOP.write(str(largeCC))
lccOP.write('\n' + '\n' + "There are " + str(len(largeCC)) + " nodes in the LCC of this graph." + '\n')
lccOP.close()
print
print ("There are " + str(len(largeCC)) + " nodes in the LCC of this graph.")
print

# Render GEXF file of LCC
print
print ("Writing gexf file of LCC... " + '\n')
runLog.write('\n' + "Writing gexf file of LCC... " + '\n')
lccSub = max(nx.connected_component_subgraphs(newEnGraph), key=len)
nx.write_gexf(lccSub, gexfLccFile)
gexfLccFile.close()

# Analysis of LCC
print ('\n' + 'Analysing LCC...' + '\n')
lccNodes = nx.number_of_nodes(lccSub)
lccEdges = nx.number_of_edges(lccSub)
lccDegreeSeq = sorted(nx.degree(lccSub).values(),reverse=True)
lccMaxDeg = max(lccDegreeSeq)
lccDensity = nx.density(lccSub)
lccAvClustering = nx.average_clustering(lccSub)
lccCl = nx.find_cliques(lccSub)
lccCl = sorted(list(lccCl), key = len, reverse = True)
lccCl_sizes = [len(c) for c in lccCl]

print ('LCC Nodes: ' + str(lccNodes))
anFile.write('LCC Nodes: ' + str(lccNodes) + '\n')
print ('LCC Edges: ' + str(lccEdges))
anFile.write('LCC Edges: ' + str(lccEdges) + '\n')
print ('LCC Density: ' + str(lccDensity))
anFile.write('LCC Density: ' + str(lccDensity) + '\n')
print ('Maximal degree of LCC: ' + str(lccMaxDeg) + '\n')
anFile.write ('Maximal degree of LCC: ' + str(lccMaxDeg) + '\n')
print ('ACC of LCC: ' + str(lccAvClustering))
anFile.write('ACC of LCC: ' + str(lccAvClustering) + '\n')
print ('Number of cliques in LCC: ' + str(len(lccCl)) + '\n')
anFile.write ('Number of cliques in LCC: ' + str(len(lccCl)) + '\n' + '\n')
print ('Size of LCC cliques: ' + str(lccCl_sizes))
anFile.write ('Size of LCC cliques: ' + str(lccCl_sizes) + '\n')
print

# Write undirected gexf file for use in Gephi
print ('\n' + 'Writing final undirected gexf file...' + '\n')
nx.write_gexf(newEnGraph, gexfFinFile)
gexfFinFile.close()

# End timing of run
endTime = datetime.now()

anFile.write ('\n' + 'Final Undirected Graph Information' + '\n' + '\n')
anFile.write ('Date of run: {}'.format(runDate) + '\n')
anFile.write ('Omega Year: ' + omegaYear + '\n')
#anFile.write ("Total artists in all genres: " + str(totalArtists) + '\n')
#anFile.write ("Total edge-weighting: " + str(int(totalEdgeWeight)) + '\n')
anFile.write ('Nodes: ' + str(nodes) + '\n')
anFile.write ('Isolated nodes: ' + str(isolateCount) + '\n')
anFile.write ('Edges: ' + str(edges) + '\n')
anFile.write ('Density: ' + str(density) + '\n')
anFile.write ('Maximal degree: ' + str(maxDeg) + '\n')
anFile.write ('Average Clustering Coefficient: ' + str(avClustering) + '\n')
anFile.write ('Number of cliques: ' + str(len(cl)) + '\n')
anFile.write ('Connected Components: ' + str(connectComp) + '\n')
anFile.write ('\n' + str(nx.info(newEnGraph)))
anFile.close()

print ('Final Undirected Graph Information' + '\n')
print ('User-entered date: ' + str(dateIP))
print ('Omega Year: ' + omegaYear)
#print ("Total artists in all genres: " + str(totalArtists))
#print ("Total edge-weighting: " + str(int(totalEdgeWeight)))
print ('Nodes: ' + str(nodes))
print ('Isolated nodes: ' + str(isolateCount))
print ('Edges: ' + str(edges))
print ('Self-loops: ' + str(selfLoopTotal))
print ('Density: ' + str(density))
print ('Maximal degree: ' + str(maxDeg))
print ('Average Clustering Coefficient: ' + str(avClustering))
print ('Number of cliques: ' + str(len(cl)))
print ('Connected Components: ' + str(connectComp))
print
print (str(nx.info(newEnGraph)))
print
print ('Date of run: {}'.format(runDate))
print ('Duration of run : {}'.format(endTime - startTime))

runLog.write ('\n' + 'Final Undirected Graph Information' + '\n' + '\n')
runLog.write ('Omega Year: ' + omegaYear + '\n')
#runLog.write ("Total artists in all genres: " + str(totalArtists) + '\n')
#runLog.write ("Total edge-weighting: " + str(int(totalEdgeWeight)) + '\n')
runLog.write ('Nodes: ' + str(nodes) + '\n')
runLog.write ('Isolated nodes:' + str(isolateCount) + '\n')
runLog.write ('Edges: ' + str(edges) + '\n')
runLog.write ('Self-loops: ' + str(selfLoopTotal) + '\n')
runLog.write ('Density: ' + str(density) + '\n')
runLog.write ('Maximal degree: ' + str(maxDeg) + '\n')
runLog.write ('Average Clustering Coefficient: ' + str(avClustering) + '\n')
runLog.write ('Number of cliques: ' + str(len(cl)) + '\n')
runLog.write ('Connected Components: ' + str(connectComp) + '\n' + '\n')
runLog.write (str(nx.info(newEnGraph)))
runLog.write ('\n' + '\n' + 'Date of run: {}'.format(runDate) + '\n')
runLog.write ('Duration of run : {}'.format(endTime - startTime) + '\n')
runLog.close()


import  pandas as  pd
import  numpy as np
from sklearn.impute import SimpleImputer
df= pd.read_csv('categorical_data.csv')
imputer = SimpleImputer(missing_values=np.NaN, strategy='mean')
"""SimpleImputer nhận hai đối số như giá trị thiếu và chiến lược.
Phương thức fit_transform được gọi trên phiên bản của SimpleImputer để xác định các giá trị còn thiếu."""
df.age = imputer.fit_transform(df['age'].values.reshape(-1,1))[:,0]
"""tìm kiếm và thay thế các giá trị còn thiếu bằng giá trị trung bình của cột age"""
df.salary = imputer.fit_transform(df['salary'].values.reshape(-1,1))[:,0]
"""tương tự với cột age"""
print(df)
print(df)
print(df.mean())
"""hiển thị ra giá trị trung bình của các cột"""
print(df.fillna(df.mean()))
"""thay thế giá trị NaN bằng giá trị trung bình của cột """
b = df['age'].mean()
print(b)
"""em thử nhưng không làm ra được ý tính gtri TB bằng cộng tay ạ """


# Initial setup following http://docs.chainer.org/en/stable/tutorial/basic.html
import numpy as np
import chainer
import six
from chainer import cuda, Function, gradient_check, report, training, utils, Variable, computational_graph
from chainer import datasets, iterators, optimizers, serializers
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L
from chainer.training import extensions

import matplotlib.pyplot as plt
import argparse

parser = argparse.ArgumentParser(description='Chainer example: MNIST')
parser.add_argument('--initmodel', '-m', default='',
                    help='Initialize the model from given file')
parser.add_argument('--batchsize', '-b', type=int, default=100,
                    help='Number of images in each mini-batch')
parser.add_argument('--epoch', '-e', type=int, default=20,
                    help='Number of sweeps over the dataset to train')
parser.add_argument('--gpu', '-g', type=int, default=-1,
                    help='GPU ID (negative value indicates CPU)')
parser.add_argument('--out', '-o', default='result/2',
                    help='Directory to output the result')
parser.add_argument('--resume', '-r', default='',
                    help='Resume the training from snapshot')
parser.add_argument('--n_units', '-u', type=int, default=50,
                    help='Number of units')

train, test = chainer.datasets.get_mnist()
args = parser.parse_args(['-g', '0'])

batchsize = args.batchsize
n_epoch = args.epoch
N = len(train)  # training data size
N_test = len(test)  # test data size

class MyChain(Chain):
    def __init__(self, n_units, n_out):
        super(MyChain, self).__init__()
        with self.init_scope():
            self.l1 = L.Linear(None, n_units)
            self.l2 = L.Linear(None, n_units)
            self.l3 = L.Linear(None, n_out)

    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        return self.l3(h2)

class SoftmaxCLassifier(Chain):
    def __init__(self, predictor):
        super(SoftmaxCLassifier, self).__init__(
            predictor=predictor
        )

    def __call__(self, x, t):
        # 在这里定义了损失函数的计算的话，就可以将此模型设置为优化器来训练
        y = self.predictor(x)
        self.loss = F.softmax_cross_entropy(y, t)
        self.accuracy = F.accuracy(y, t)
        return self.loss

# init
n_units = args.n_units
model = MyChain(n_units, 10)
classifier_model = SoftmaxCLassifier(model)
# Setup an optimizer
optimizer = chainer.optimizers.Adam()
optimizer.setup(classifier_model)
# Pass the loss function (Classifier defines it) and its arguments
# optimizer.update(classifier_model, x, t)

# 如果不是使用gpu就把变量gpu设置为-1
gpu = 0
if gpu >= 0:
    chainer.cuda.get_device(gpu).use()  # Make a specified GPU current
    classifier_model.to_gpu()  # Copy the model to the GPU
#     cuda.cupy相当于numpy的gpu版本
xp = np if gpu < 0 else cuda.cupy

if args.initmodel:
    print('Load model from', args.initmodel)
    serializers.load_npz(args.initmodel, classifier_model)
if args.resume:
    print('Load optimizer state from', args.resume)
    serializers.load_npz(args.resume, optimizer)
import os
if not os.path.exists(args.out):
    os.makedirs(args.out)
import time
for epoch in range(1, n_epoch + 1):
    print('epoch', epoch)

    # training
    perm = np.random.permutation(N)
    sum_accuracy = 0
    sum_loss = 0
    start = time.time()
    for i in range(0, N, batchsize):
        x = chainer.Variable(xp.asarray(train[perm[i:i + batchsize]][0]))
        t = chainer.Variable(xp.asarray(train[perm[i:i + batchsize]][1]))

        # Pass the loss function (Classifier defines it) and its arguments
        optimizer.update(classifier_model, x, t)

        if epoch == 1 and i == 0:
            with open('{}/graph.dot'.format(args.out), 'w') as o:
                g = computational_graph.build_computational_graph(
                    (classifier_model.loss,))
                o.write(g.dump())
            print('graph generated')

        sum_loss += float(classifier_model.loss.data) * len(t.data)
        sum_accuracy += float(classifier_model.accuracy.data) * len(t.data)
    end = time.time()
    elapsed_time = end - start
    throughput = N / elapsed_time
    print('train mean loss={}, accuracy={}, throughput={} images/sec'.format(
        sum_loss / N, sum_accuracy / N, throughput))

    # evaluation
    sum_accuracy = 0
    sum_loss = 0
    for i in six.moves.range(0, N_test, batchsize):
        index = np.asarray(list(range(i, i + batchsize)))
        x = chainer.Variable(xp.asarray(test[index][0]))
        t = chainer.Variable(xp.asarray(test[index][1]))
        with chainer.no_backprop_mode():
            # When back propagation is not necessary,
            # we can omit constructing graph path for better performance.
            # `no_backprop_mode()` is introduced from chainer v2,
            # while `volatile` flag was used in chainer v1.
            loss = classifier_model(x, t)
        sum_loss += float(loss.data) * len(t.data)
        sum_accuracy += float(classifier_model.accuracy.data) * len(t.data)

    print('test mean loss={}, accuracy={}'.format(
        sum_loss / N_test, sum_accuracy / N_test))


import torch
import pandas as pd

class CSVDataset(torch.utils.data.Dataset):

    def __init__(self, x_csv_path, window_length = 50):

        # load csv file as dataframe

        self.x = pd.read_csv(x_csv_path,header = None)

        # specify how many samples in a window

        self.window_length = window_length

    def __len__(self): # number of windows

        return int(len(self.x) / self.window_length)

    def __getitem__(self,idx):

        # get sample numbers for window start and end

        start = idx*self.window_length
        end = start + self.window_length

        # extract window and convert to NumPy array

        window = self.x.iloc[start:end,2].to_numpy(copy = True)

        # convert window to torch column tensor

        window = torch.from_numpy(window)

        # convert to one-hot encoding

        window = torch.nn.functional.one_hot(window - 1).to(torch.float)

        return window

if __name__ == '__main__':

    path = '../data/train.csv'
    dataset = CSVDataset(path)

    x = dataset[len(dataset)-1]


#https://www.hackerrank.com/challenges/apple-and-orange/problem?isFullScreen=true&h_r=next-challenge&h_v=zen

# !/bin/python3

import math
import os
import random
import re
import sys

# Complete the 'countApplesAndOranges' function below.
#
# The function accepts following parameters:
#  1. INTEGER s
#  2. INTEGER t
#  3. INTEGER a
#  4. INTEGER b
#  5. INTEGER_ARRAY apples
#  6. INTEGER_ARRAY oranges
#

def countApplesAndOranges(s, t, a, b, apples, oranges):
    # Write your code here
    apples_on_house, oranges_on_house = 0, 0
    for i in apples:
        if i >= (s - a) and i <= (t - a):
            apples_on_house += 1
    for i in oranges:
        if -i >= (b - t) and -i <= (b - s):
            oranges_on_house += 1
    print(apples_on_house)
    print(oranges_on_house)

if __name__ == '__main__':
    first_multiple_input = input().rstrip().split()
    s = int(first_multiple_input[0])
    t = int(first_multiple_input[1])
    second_multiple_input = input().rstrip().split()
    a = int(second_multiple_input[0])
    b = int(second_multiple_input[1])
    third_multiple_input = input().rstrip().split()
    m = int(third_multiple_input[0])
    n = int(third_multiple_input[1])
    apples = list(map(int, input().rstrip().split()))
    oranges = list(map(int, input().rstrip().split()))
    countApplesAndOranges(s, t, a, b, apples, oranges)


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

import numpy as np
import pandas as pd
import lightgbm as lgb
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_absolute_error
from sklearn.manifold import LocallyLinearEmbedding

import pickle
import plotly.graph_objs as go
import os
import streamlit as st
import datetime
pd.set_option('plotting.backend', 'plotly')
import warnings

warnings.filterwarnings('ignore')

test_length = 7
model_path_C3 = 'pages/liquidC3_lgb.bin'
model_path_C2 = 'pages/liquidC2_lgb.bin'
model_path_C1 = 'pages/liquidC1_lgb.bin'

if __name__ == '__main__':
    df_gas_liquid = pd.read_csv('dataset/LiquidProduction.csv')
    df_gas_liquid['Date'] = pd.to_datetime(df_gas_liquid['Date'])
    df_gas_liquid['elapsed'] = (df_gas_liquid['Date'] - df_gas_liquid['Date'][0]).apply(lambda x: x.days) + 1

    lag_days = [i for i in range(1, 5)]
    df_gas_liquid = df_gas_liquid.assign(**{
        'lag_{}_C1'.format(l): df_gas_liquid['LiquidProductionC1'].transform(lambda x: x.shift(l)) for l in
        lag_days})
    df_gas_liquid = df_gas_liquid.assign(**{
        'lag_{}_C2'.format(l): df_gas_liquid['LiquidProductionC2'].transform(lambda x: x.shift(l)) for l in
        lag_days})
    df_gas_liquid = df_gas_liquid.assign(**{
        'lag_{}_C3'.format(l): df_gas_liquid['LiquidProductionC3'].transform(lambda x: x.shift(l)) for l in
        lag_days})

    featuresC1 = ['elapsed', 'GasProductionC1']  # + ['lag_{}_C1'.format(i) for i in lag_days]
    featuresC2 = ['elapsed', 'GasProductionC2']  # + ['lag_{}_C2'.format(i) for i in lag_days]
    featuresC3 = ['elapsed', 'GasProductionC3']  # + ['lag_{}_C3'.format(i) for i in lag_days]

    lgb_params = {
        'boosting_type': 'gbdt',
        'objective': 'regression',
        'metric': 'mae',
        'num_leaves': 30,
        'min_data_in_leaf': 4,  # 叶子结点的最小数据数，避免过拟合
        'max_depth': 6,  # 单颗树的最大深度
        'subsample': 0.8,
        'colsample_bytree': 0.8,
        'learning_rate': 0.05,
        'max_bin': 1000,
        'n_estimators': 1000,
        'verbose': -1,
    }

    X_train_C1 = df_gas_liquid[featuresC1].iloc[:-test_length, :]
    y_train_C1 = df_gas_liquid['LiquidProductionC1'][:-test_length]
    X_test_C1 = df_gas_liquid[featuresC1].iloc[-test_length:, :]
    y_test_C1 = df_gas_liquid['LiquidProductionC1'][-test_length:]
    train_data_C1 = lgb.Dataset(X_train_C1, y_train_C1)
    if not os.path.exists(model_path_C1):
        regressor_C1 = lgb.train(lgb_params, train_data_C1, verbose_eval=100)
        pickle.dump(regressor_C1, open(model_path_C1, 'wb'))
    else:
        regressor_C1 = pickle.loads(open(model_path_C1, 'rb').read())
    y_pred_C1 = regressor_C1.predict(X_test_C1)
    mae = mean_absolute_error(y_test_C1, y_pred_C1)
    print('C1 MAE: {}'.format(mae))

    X_train_C2 = df_gas_liquid[featuresC2].iloc[:-test_length, :]
    y_train_C2 = df_gas_liquid['LiquidProductionC2'][:-test_length]
    X_test_C2 = df_gas_liquid[featuresC2].iloc[-test_length:, :]
    y_test_C2 = df_gas_liquid['LiquidProductionC2'][-test_length:]
    train_data_C2 = lgb.Dataset(X_train_C2, y_train_C2)
    if not os.path.exists(model_path_C2):
        regressor_C2 = lgb.train(lgb_params, train_data_C2, verbose_eval=100)
        pickle.dump(regressor_C2, open(model_path_C2, 'wb'))
    else:
        regressor_C2 = pickle.loads(open(model_path_C2, 'rb').read())
    y_pred_C2 = regressor_C2.predict(X_test_C2)
    mae = mean_absolute_error(y_test_C2, y_pred_C2)
    print('C2 MAE: {}'.format(mae))

    X_train_C3 = df_gas_liquid[featuresC3].iloc[:-test_length, :]
    y_train_C3 = df_gas_liquid['LiquidProductionC3'][:-test_length]
    X_test_C3 = df_gas_liquid[featuresC3].iloc[-test_length:, :]
    y_test_C3 = df_gas_liquid['LiquidProductionC3'][-test_length:]
    train_data_C3 = lgb.Dataset(X_train_C3, y_train_C3)
    if not os.path.exists(model_path_C3):
        regressor_C3 = lgb.train(lgb_params, train_data_C3, verbose_eval=100)
        pickle.dump(regressor_C3, open(model_path_C3, 'wb'))
    else:
        regressor_C3 = pickle.loads(open(model_path_C3, 'rb').read())
    y_pred_C3 = regressor_C3.predict(X_test_C3)
    mae = mean_absolute_error(y_test_C3, y_pred_C3)
    print('C3 MAE: {}'.format(mae))

    regressor = {'C1': regressor_C1, 'C2': regressor_C2, 'C3': regressor_C3}
    st.header("产液量预测")
    station = st.sidebar.selectbox(label='请选择集气站', options=['C1', 'C2', 'C3'], index=2)
    date_input = st.sidebar.date_input(label='请输入当前日期', value=pd.to_datetime('2021-12-31'))
    elasped = (pd.to_datetime(date_input) - df_gas_liquid['Date'][0]).days + 1
    gas_production = st.sidebar.number_input('请输入当日预计产气量', value=395.75)
    # lag_1 = st.sidebar.number_input(str(pd.to_datetime(date_input) - datetime.timedelta(days=1))[:10] + ' ' + station + ' 产液量:', value=142.78)
    # lag_2 = st.sidebar.number_input(str(pd.to_datetime(date_input) - datetime.timedelta(days=2))[:10] + ' ' + station + ' 产液量:', value=105.94)
    # lag_3 = st.sidebar.number_input(str(pd.to_datetime(date_input) - datetime.timedelta(days=3))[:10] + ' ' + station + ' 产液量:', value=128.68)
    # lag_4 = st.sidebar.number_input(str(pd.to_datetime(date_input) - datetime.timedelta(days=4))[:10] + ' ' + station + ' 产液量:', value=99.55)
    with st.form("my_form"):
        submitted = st.form_submit_button("submit")
        if submitted:
            # forecast = regressor[station].predict([[elasped, gas_production, lag_1, lag_2, lag_3, lag_4]])
            forecast = regressor[station].predict([[elasped, gas_production]])

            st.write('*'+str(pd.to_datetime(date_input))[:10] + ' ' + station + ' 预测产液量:   {}*'.format(forecast[0]))

    st.subheader('测试结果展示')
    fig = go.Figure()
    fig.add_trace(go.Scatter(
        x=df_gas_liquid['Date'][-test_length:],
        y=y_test_C1,
        name='Actual'
    ))

    fig.add_trace(go.Scatter(
        x=df_gas_liquid['Date'][-test_length:],
        y=y_pred_C1,
        name='Forecast'
    ))
    fig.update_layout(title_text='C1 预测产液量和真实产液量')
    st.plotly_chart(fig)

    fig = go.Figure()
    fig.add_trace(go.Scatter(
        x=df_gas_liquid['Date'][-test_length:],
        y=y_test_C2,
        name='Actual'
    ))

    fig.add_trace(go.Scatter(
        x=df_gas_liquid['Date'][-test_length:],
        y=y_pred_C2,
        name='Forecast'
    ))
    fig.update_layout(title_text='C2 预测产液量和真实产液量')
    st.plotly_chart(fig)

    fig = go.Figure()
    fig.add_trace(go.Scatter(
        x=df_gas_liquid['Date'][-test_length:],
        y=y_test_C3,
        name='Actual'
    ))

    fig.add_trace(go.Scatter(
        x=df_gas_liquid['Date'][-test_length:],
        y=y_pred_C3,
        name='Forecast'
    ))
    fig.update_layout(title_text='C3 预测产液量和真实产液量')
    st.plotly_chart(fig)


# -*- coding: utf-8 -*-
# @Time    : 2022/9/7 17:47
# @Author  : 崔文帅
# @File    : daydayup.py

dayday_up = pow(1.001, 365)#一天进步千分之一
dayday_down = pow(0.999, 365)#一天退步千分之一

basic = 1.0
rate= 0.001
for i in range(365):
    if i % 5 in range(1,4):
        dayup = basic*(1-rate)
    else:
        dayup = basic*(1+rate)
print("一天进步千分之一："+str(dayday_up))
print("一天退步千分之一："+str(dayday_down))
print("三天打鱼两天晒网："+str(dayup))


# file: mock_config.py
# DO NOT MODIFY THIS FILE. IT IS USED FOR TESTING AND MUST REMAIN AS IT IS FOR TESTS TO PASS.  # noqa: E501

src = 'test'  # what microcontroller is generating the signals

input_names = ["A1", "D2", "D3"]  # what pins are going to be sampled for this app  # noqa: E501

#  **************** Lookups ********************************************
#  Lookup for number of samples to be averaged, key: A2D  value: num
analog_num_lookup = {25: 10, 50: 10, 100: 10, 2048: 10}   # for testing
db_interval_lookup = {30: 30, 100: 30, 200: 30, 400: 30, 500: 30, 2048: 30}  # for testing  # noqa: E501

#  **************** Values *********************************************

initial_db_interval = 60         # seconds
# following is for info only. Change it for your path. The actual path is determined by startup of server.  # noqa: E501
db_file_path = '/Users/garth/Programming/python3/py3-arduino_fastapi_GuI/sql_app/signals.db'  # noqa: E501

initial_analog_num = 10

analog_3sigma = 0   # to relax this constraint, set it to 0

digital_num = 5

usb_port = '/dev/cu.usbmodem14301'

db_url = 'http://127.0.0.1:8000/pins/'
# for later work using nosql on a free public platform, ids are for me only
deta_db_url = 'https://sfwfom.deta.dev'
deta_projectId = 'b0uggz3e'
deta_microId = '58935fb8-1266-40bb-9499-c833071ce576'


# Problem Statement: https://leetcode.com/problems/swap-nodes-in-pairs/

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def swapPairs(self, head):
        if not head or not head.next: return head
        dummy = ListNode(0)
        dummy.next = head
        current = dummy

        while current.next and current.next.next:
            first = current.next
            second = current.next.next
            current.next = second
            first.next = second.next
            second.next = first
            current = current.next.next
        return dummy.next


import configparser
import json
#address_create_notify == get btc or bch address
import pprint
import os
import sys
from filelock import FileLock
from datetime import datetime
from rss_feed import add_to_rfeed
import time
from helper_create import wish_prompt
config = ""
sys.path.insert(1, './static/')
from static_html_loop import main as static_main
import sqlite3
import uuid
import notify_xmr_vps_pi
import asyncio

def main():
    global config
    print('''Wishlist editor.
        this script assumes that your wishlist is running already.
        Lets begin!''')
    config = configparser.ConfigParser()
    config.read('./db/wishlist.ini')
    if not os.path.isfile("./static/data/wishlist-data.json"):
        print("Error: please run setup_wallets.py first.")
        sys.exit(1)

    with open("./static/data/wishlist-data.json", "r") as f:
        wishlist = json.load(f)
    if not wishlist["wishlist"]:
        print("Empty wishlist detected. Please add a wish")
        wish_prompt(config)
        return

    #for i in range(len(wishlist["wishlist"])):
    #    print(f"{i}) {wishlist['wishlist'][i]['title']}")
    print("1) Add a wish")
    print("2) Remove")
    print("3) Edit")
    print("4) Delete Comments")
    print("5) Show 'wallet gap limits' (BCH/BTC)")
    answer = ""
    while answer not in [1,2,3,4,5]:
        answer = int(input("Enter 1 2 or 3 >> "))
    if answer == 1:
        wish_prompt(config)
    if answer == 2:
        wish_edit(wishlist,"Delete",config["wishlist"]["www_root"])
    if answer == 3:
        wish_edit(wishlist,"Edit",config["wishlist"]["www_root"])
    if answer == 4:
        delete_comments(wishlist)
    if answer == 5:
        get_gap_limits()

    #blindly trigger a static html refresh
    static_main(config)
    #does not work as expected
    #front end refreshes existing data - not redraws
    uid = uuid.uuid4().hex
    asyncio.run(notify_xmr_vps_pi.ws_work_around(uid))

def delete_comments(wishlist):
    total = 0
    total = len(wishlist["comments"]["comments"])
    if total == 0:
        print("No comments to delete")
        return
    for i in range(total):
        comment = wishlist["comments"]["comments"][i]
        print(f"Comment number: {i}")
        print(f'User: {comment["comment_name"]}')
        print(f'Comment: {comment["comment"]}')
        print("------------------------------------------")
    del_me = -1
    while del_me not in range(0,total):
        print(f"Enter comment number to delete:")
        del_me = int(input(">> "))

    print("Delete this comment:")
    print(wishlist["comments"]["comments"][int(del_me)]["comment"])
    answer = ""
    while "y" not in answer.lower() and "n" not in answer.lower():
        answer = input("Yes/No >> ")
        print(answer.lower())
    if "y" in answer.lower():
        #delete
        wishlist["comments"]["comments"].pop(int(del_me))
    else:
        print("Ooops, run edit_wishlist.py again")

    with open("./static/data/wishlist-data.json","w") as f:
        json.dump(wishlist,f, indent=6)

def get_gap_limits():
    #count total number of addresses given
    con = sqlite3.connect('./db/receipts.db')
    cur = con.cursor()
    create_receipts_table = """ CREATE TABLE IF NOT EXISTS donations (
                                email text,
                                amount integer default 0 not null,
                                fname text,
                                donation_address text PRIMARY KEY,
                                zipcode text,
                                address text,
                                date_time text,
                                refund_address text,
                                crypto_ticker text,
                                wish_id text,
                                comment text,
                                comment_name text,
                                amount_expected integer default 0 not null,
                                consent integer default 0,
                                quantity integer default 0,
                                type text,
                                comment_bc integer default 0
                            ); """

    cur.execute(create_receipts_table)
    cur.execute('SELECT * FROM donations WHERE crypto_ticker = ?',["bch"])
    gap = len(cur.fetchall())
    gap += 20
    print(f"BCH gap limit : {gap}")
    print(f"To see all donations enter this in the Electron-cash wallet console:")
    print(f">> for i in range(0, {gap}): print(wallet.create_new_address(False))")
    print(f"------------------------------------------------")
    cur.execute('SELECT * FROM donations WHERE crypto_ticker = ?',["btc"])
    gap = len(cur.fetchall())
    gap += 20
    print(f"BTC gap limit : {gap}")
    print(f"To see all donations enter this in the Electrum wallet console:")
    print(f">> for i in range(0, {gap}): print(wallet.create_new_address(False))")
    print(f"------------------------------------------------")
    con.commit()
    con.close()

#find the matching wish and set the variables
def wish_edit(wishlist,edit_delete,www_root):
    returned_list = {"hello":"world"}
    print(f"Which wish would you like to {edit_delete}")
    for i in range(len(wishlist["wishlist"])):
        offset = i
        offset += 1
        print(f"{offset}) {wishlist['wishlist'][i]['title']}")
    index = ""
    end = len(wishlist["wishlist"])
    end += 1
    while index not in range(1,end):
        index = int(input(f"Pick a wish to Edit (1-{offset}) >> "))

    index -= 1
    if edit_delete == "Edit":
        while True:
            #title
            print(f"Edit Wish: {wishlist['wishlist'][index]['title']}")
            print("1) Title")
            print("2) Goal")
            print("3) Description")
            print("4) Add monthly fee (e.g. -$100 / month")
            print("5) Status (WIP / RELEASED)")
            print("6) Totals")
            answer = ""
            goal = ""
            description = ""
            cost = ""
            title = ""
            while answer not in [1,2,3,4,5,6]:
                answer = int(input(">> "))
            if answer == 1:
                wishlist["wishlist"][index]["title"] = input("New title >> ")
            if answer == 2:
                while not goal.isnumeric():
                    goal = input("New $Goal >> ")
                wishlist["wishlist"][index]["goal_usd"] = goal
            if answer == 3:
                wishlist["wishlist"][index]["description"] = input("New Description >> ")
            if answer == 4:
                while not cost.isnumeric():
                    cost = input("Cost of the recurring amount in USD e.g. 100 >> ")
                wishlist["wishlist"][index]["type"] = "recurring:" + str(cost)
                #pprint.pprint(wishlist["wishlist"][index])
                wish_id = wishlist["wishlist"][index]["xmr_address"][0:12]
                insert_recurring(wish_id)
            if answer == 5:
                wishlist["wishlist"][index]["status"] = input("New Status >> ")
            if answer == 6:
                total_xmr = wishlist["wishlist"][index]["xmr_total"]
                total_bch = wishlist["wishlist"][index]["bch_total"]
                total_btc = wishlist["wishlist"][index]["btc_total"]
                total_usd = wishlist["wishlist"][index]["usd_total"]
                total_wow = wishlist["wishlist"][index]["wow_total"]
                goal = wishlist["wishlist"][index]["goal_usd"]
                choice = {"1": "xmr", "2": "bch", "3": "btc", "4": "usd","5": "wow"}
                print("Coin [total]")
                print(f"1) XMR [{total_xmr}]")
                print(f"2) BCH [{total_bch}]")
                print(f"3) BTC [{total_btc}]")
                print(f"4) USD [{total_usd}]")
                print(f"5) WOW [{total_wow}]")
                answer = 7
                while answer not in [1,2,3,4,5]:
                    answer = int(input(">> "))
                    coin = choice[str(answer)]
                    while True:
                        try:
                            userInput = input(f"Enter the new total for {coin}\n>>")
                            val = float(userInput)
                            break
                        except ValueError:
                            print("That's not an int!")
                    wishlist["wishlist"][index][f"{coin}_total"] = val

            again = 0
            finish = ""
            while finish.lower() not in ["y","yes","no","n"]:
                finish = input("Edit this wish again? y/n >> ")
            if "n" in finish.lower():
                print("saving edits")
                data_json = os.path.join(www_root,"data","wishlist-data.json")
                with open(data_json,"r") as f:
                    now_wishlist = json.load(f)
                for i in range(len(now_wishlist["wishlist"])):
                    if now_wishlist["wishlist"][i]["xmr_address"] == wishlist["wishlist"][index]["xmr_address"]:
                        now_wishlist["wishlist"][i]["goal_usd"] = wishlist["wishlist"][index]["goal_usd"]
                        now_wishlist["wishlist"][i]["title"] = wishlist["wishlist"][index]["title"]
                        now_wishlist["wishlist"][i]["description"] = wishlist["wishlist"][index]["description"]
                        now_wishlist["wishlist"][i]["type"] = wishlist["wishlist"][index]["type"]
                        now_wishlist["wishlist"][i]["status"] = wishlist["wishlist"][index]["status"]
                        now_wishlist["wishlist"][i]["xmr_total"] = wishlist["wishlist"][index]["xmr_total"]
                        now_wishlist["wishlist"][i]["xmr_total"] = wishlist["wishlist"][index]["bch_total"]
                        now_wishlist["wishlist"][i]["btc_total"] = wishlist["wishlist"][index]["btc_total"]
                        now_wishlist["wishlist"][i]["usd_total"] = wishlist["wishlist"][index]["usd_total"]
                        now_wishlist["wishlist"][i]["wow_total"] = wishlist["wishlist"][index]["wow_total"]
                        break
                lock = FileLock(f"{data_json}.lock")
                with lock:
                    with open(data_json, "w+") as f:
                        json.dump(now_wishlist, f, indent=2)
                break
    if edit_delete == "Delete":
        while True:
            answer = input(f"Delete: {wishlist['wishlist'][index]['title']} \n Are you sure?")
            if "y" in answer.lower():
                wishlist = delete_wish(wishlist,index)
                break
    #pprint.pprint(wishlist)
    with open("./static/data/wishlist-data.json","w") as f:
        json.dump(wishlist,f, indent=6)

def insert_recurring(wish_id):
    con = sqlite3.connect('./db/recurring_fees.db')
    cur = con.cursor()
    create_fees_table = """ CREATE TABLE IF NOT EXISTS fees (
                                wish_id text PRIMARY KEY
                            ); """

    cur.execute(create_fees_table)
    cur.execute('SELECT * FROM fees WHERE wish_id = ?',[wish_id])
    rows = cur.fetchall()
    #insert if not in db already
    if not len(rows):
        cur.execute('INSERT INTO fees VALUES(?)',[wish_id])
        con.commit()
    con.close()

#tidy this up
def delete_wish(wishlist,index):
    global config
    deleted = wishlist["wishlist"][index]
    www_root = config["wishlist"]["www_root"]
    now_wishlist = wishlist
    for i in range(len(now_wishlist["wishlist"])):
        if now_wishlist["wishlist"][i]["xmr_address"] == deleted["xmr_address"]:
            archive = now_wishlist["wishlist"][i]
            now_wishlist["wishlist"].pop(i)
            break
    now_wishlist["archive"].append(archive)
    data_json = './static/data/wishlist-data.json'
    lock = FileLock(f"{data_json}.lock")
    with lock:
        with open(data_json, "w+") as f:
            json.dump(now_wishlist, f, indent=2)
    #error because wish might not be in fees / or not exist yet
    con = sqlite3.connect('./db/recurring_fees.db')
    cur = con.cursor()
    wish_id = deleted["id"]
    try:
        cur.execute('DELETE FROM fees WHERE wish_id=?',[wish_id])
    except:
        pass
    con.commit()
    con.close()
    return now_wishlist
    #lets find the wish in our data.json file in www_root

main()