from torch.utils.data import Dataset
import torch
from PIL import Image
from pathlib import Path
import numpy as np
from dataclasses import dataclass
import random

@dataclass
class imageset:
    t1: Path
    t2: Path
    cm: Path

@dataclass
class patch:
    imset: imageset
    x: tuple
    y: tuple

class CDDataset(Dataset):
    """"""

    imagesets = None
    patchsize = None
    nx = 0
    ny = 0
    patches = []
    normalize = True

    cache = {}

    def loadrgb(self, image):
        if image not in self.cache:
            img = self._loadrgb(image).astype(np.float32)
            if self.normalize:
                img = (img - img.mean(axis=(-1, -2))[:, None, None]) / img.std(
                    axis=(-1, -2)
                )[:, None, None]
            self.cache[image] = img
        return self.cache[image]

    def loadcm(self, image):
        if image not in self.cache:
            self.cache[image] = self._loadcm(image).astype(np.int64)
        return self.cache[image]

    def __init__(self):
        if self.imagesets is None or self.patchsize is None:
            raise NotImplementedError
        m, v = np.zeros(3), np.zeros(3)
        self.patches = []
        for imset in self.imagesets:
            im1 = self.loadrgb(imset.t1)
            im2 = self.loadrgb(imset.t2)
            cm = self.loadcm(imset.cm)
            assert im1.shape[1:] == im2.shape[1:] == cm.shape
            assert im1.shape[0] == im2.shape[0] == 3
            for ix in range(im1.shape[1] // self.patchsize):
                for iy in range(im1.shape[2] // self.patchsize):
                    self.patches.append(
                        patch(
                            imset,
                            (self.patchsize * ix, self.patchsize * (ix + 1)),
                            (self.patchsize * iy, self.patchsize * (iy + 1)),
                        )
                    )
            self.nx += ix / len(self.imagesets)
            self.ny += iy / len(self.imagesets)
        self._m = m
        self._s = np.sqrt(v)

    def __getitem__(self, idx):
        patch = self.patches[idx]
        im1 = self.loadrgb(patch.imset.t1)
        im2 = self.loadrgb(patch.imset.t2)
        cm = self.loadcm(patch.imset.cm)
        im1 = im1[..., patch.x[0] : patch.x[1], patch.y[0] : patch.y[1]]
        im2 = im2[..., patch.x[0] : patch.x[1], patch.y[0] : patch.y[1]]
        #         if self.normalize:
        #           im1=(im1-im1.mean(axis=(-1,-2))[:,None,None])/im1.std(axis=(-1,-2))[:,None,None]
        #           im2=(im2-im2.mean(axis=(-1,-2))[:,None,None])/im2.std(axis=(-1,-2))[:,None,None]
        cm = cm[..., patch.x[0] : patch.x[1], patch.y[0] : patch.y[1]]
        return (im1, im2, cm)

    def __len__(self):
        return len(self.patches)

class WV_S1(CDDataset):
    def __init__(self, path: Path, patchsize: int):
        self.imagesets = [imageset(*(path / f for f in ["t1.bmp", "t2.bmp", "gt.bmp"]))]
        self.patchsize = patchsize
        super(WV_S1, self).__init__()

    def _loadrgb(self, image):
        return np.array(Image.open(image)).transpose(2, 0, 1) / 255

    def _loadcm(self, image):
        return np.array(Image.open(image)) < 128

class OSCD(CDDataset):
    def __init__(self, path: Path, patchsize: int):

        self.imagesets = [
            imageset(im1, im2, cm)
            for im1, im2, cm in zip(
                sorted((path / "images").rglob("imgs_1_rect")),
                sorted((path / "images").rglob("imgs_2_rect")),
                sorted((path / "labels").rglob("cm")),
            )
        ]
        self.patchsize = patchsize
        super(OSCD, self).__init__()

    def _loadrgb(self, image):
        return np.stack(
            [np.array(Image.open(image / b)) for b in ("B02.tif", "B03.tif", "B04.tif")]
        )

    def _loadcm(self, image):
        return np.array(Image.open(next(image.glob("*-cm.tif")))) > 1

from typing import Tuple
from torch.utils.data import Subset

def split(
    ds: Dataset, validation_ratio: float, test_ratio: float, runsize=16, seed=0
) -> Tuple[Dataset, Dataset, Dataset]:
    """
    splits dataset by ratio (0..1) of validation and test in validation, test and train (remainder)
    while ensuring somewhat equal distribution between different parts
    of the Dataset by randomly choosing out of partitions of size runsize
    """
    rng = np.random.RandomState(0)
    val = list()
    test = list()
    train = list()
    split = np.array_split(np.arange(len(ds)), len(ds) / runsize)
    for s in split:
        nv = int(
            validation_ratio * (len(val) + len(test) + len(train) + len(s)) - len(val)
        )
        i = rng.choice(s, nv, replace=False)
        s = np.setdiff1d(s, i)
        val += i.tolist()
        nt = int(test_ratio * (len(val) + len(test) + len(train) + len(s)) - len(test))
        i = rng.choice(s, nt, replace=False)
        s = np.setdiff1d(s, i)
        test += i.tolist()
        train += s.tolist()
    return CDSubset(ds, train), CDSubset(ds, val), CDSubset(ds, test)

class CDSubset(Subset):
    """
    Subset of a CDDataset at specified indices with optional augmentation.
    """

    augment = False

    def __getitem__(self, idx):
        items = super().__getitem__(idx)
        if self.augment:
            if random.randint(0, 1):
                items = [np.swapaxes(item, -1, -2) for item in items]
            rot = random.randint(0, 3)
            items = [np.copy(np.rot90(item, rot, (-1, -2))) for item in items]
        return items

class CDCat(Dataset):
    """
    Concats the two images along first dimension
    """
    def __init__(self, baseObject):
        self.__class__ = type(baseObject.__class__.__name__,
                  (self.__class__, baseObject.__class__),
                  {})
        self.__dict__ = baseObject.__dict__
        self.baseObject=baseObject
    def __getitem__(self, idx):
        im1, im2, cm = self.baseObject[idx]
        return np.concatenate((im1,im2),0),cm


from vtk import *

# input data, every row is for a different item
positions = [[0, 0, 0],[1.5, 0, 0]]

orientations = [[1.0, 0.0, 0.0],[0.0, 1.0, 1.0]]

colors = [[255, 0, 0],
          [0, 255, 255]]

heights = [1,
           2]

# rendering of those two defined cylinders
points = vtkPoints()
points.InsertNextPoint(*positions[0])
points.InsertNextPoint(*positions[1])
polydata = vtkPolyData()
polydata.SetPoints(points)

color_def = vtkUnsignedCharArray()
color_def.SetNumberOfComponents(3)
color_def.SetNumberOfTuples(polydata.GetNumberOfPoints())
color_def.InsertTuple3(0, *colors[0])
color_def.InsertTuple3(1, *colors[1])
polydata.GetPointData().SetScalars(color_def)

pointNormalsArray = vtkDoubleArray()
pointNormalsArray.SetNumberOfComponents(3)
pointNormalsArray.SetNumberOfTuples(polydata.GetNumberOfPoints())
pointNormalsArray.SetTuple(0, orientations[0])
pointNormalsArray.SetTuple(1, orientations[1])
polydata.GetPointData().SetNormals(pointNormalsArray)

cyl_source = vtkCylinderSource()
cyl_source.SetResolution(10)
cyl_source.SetHeight(0.8)
cyl_source.SetRadius(0.1)
cyl_source.Update()

glyph = vtkGlyph3D()
glyph.SetInputData(polydata)
glyph.SetSourceConnection(cyl_source.GetOutputPort())
glyph.SetColorModeToColorByScalar()
glyph.SetVectorModeToUseNormal()
glyph.ScalingOff()

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(glyph.GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)
ren = vtkRenderer()
ren.AddActor(actor)

renwin = vtk.vtkRenderWindow()
renwin.AddRenderer(ren)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renwin)
renwin.Render()
iren.Initialize()
iren.Start()


from obspy import read
from numpy import r_,ones,zeros

path=u'/Users/dmelgar/Slip_inv/Chiapas_hernandez_new/data/waveforms/before_delta_t/'
outpath='/Users/dmelgar/Slip_inv/Chiapas_hernandez_new/data/waveforms/'

def delay_st(st,delta):
    d=st[0].data
    npts=int(abs(delta)/st[0].stats.delta)
    if delta<0:
        d=r_[d[npts:-1],d[-1]*ones(npts+1)]
    else:
        d=r_[ones(npts)*d[0],d[0:-npts]]
    return d

sta='43413'
delta=-3*60.
e=read(path+sta+'.sac')
e[0].data=delay_st(e,delta)
e.write(outpath+sta+'.sac',format='SAC')

sta='huat'
delta=-2*60.
e=read(path+sta+'.sac')
e[0].data=delay_st(e,delta)
e.write(outpath+sta+'.sac',format='SAC')

sta='ptan'
delta=-2*60.
e=read(path+sta+'.sac')
e[0].data=delay_st(e,delta)
e.write(outpath+sta+'.sac',format='SAC')


#!/usr/bin/python3
#encoding: UTF-8

import lxml.etree as ET
import markdown as MD
import lib as LIB

#-------------------------------------------------------------------------------
def xpath_list(from_node, xpath):
  """
     Return all nodes matching xpath from from_node as dom node list.
  """
  if isinstance(from_node, ET._Element):
    ret = from_node.xpath(xpath)
  else:
    ret=[]

  return ret

#-------------------------------------------------------------------------------
def xpath_num_sorted(from_node, xpath, xp_key):
  """
     Return all nodes matching xpath from from_node as dom node list num sorted
     on xp_key xpath (relative to each item).
  """
  all = xpath_list(from_node, xpath)
  all_sorted = sorted(all, key=lambda itm: xpath_int(itm, xp_key))
  return all_sorted

#-------------------------------------------------------------------------------
def xpath_alpha_sorted(from_node, xpath, xp_key):
  """
     Return all nodes matching xpath from from_node as dom node list alpha sorted
     on xp_key xpath (relative to each item).
  """
  all = xpath_list(from_node, xpath)
  all_sorted = sorted(all, key=lambda itm: xpath_plain(itm, xp_key))
  return all_sorted

#-------------------------------------------------------------------------------
def xpath_node(from_node, xpath):
  """
     Return first node matching xpath from from_node as dom node.
  """
  return LIB.first(xpath_list(from_node, xpath))

#-------------------------------------------------------------------------------
def xpath_plain(from_node, xpath):
  """
     Return first node matching xpath from from_node as plain text.
  """
  return LIB.first_str(xpath_list(from_node, xpath))

#-------------------------------------------------------------------------------
def xpath_int(from_node, xpath):
  """
     Return first node matching xpath from from_node as integer.
  """
  return int(LIB.first_str(xpath_list(from_node, xpath)))

#-------------------------------------------------------------------------------
def xpath_md(from_node, xpath):
  """
     Return first node matching xpath from from_node as markdown translated to HTML.
     /!\ just for simple paragraphs (no images, no extern refs...)
  """
  return MD.markdown(LIB.first_str(xpath_list(from_node, xpath)))

#-------------------------------------------------------------------------------
def add_error(meta, fct, errlevel, errno, errmsg, line, text):
  """
     Add new error to meta node of an XML document.
  """
  if (meta is not None):
    err_node = ET.SubElement(meta, "error", {"fct":fct, "errlevel":errlevel, "errno":errno, "errmsg":errmsg, "line":str(line)})
    err_node.text = str(text)
    ret = err_node

  else:
    ret = None

  return ret

#-------------------------------------------------------------------------------
def add_external_ref(meta, ext_ref, from_ref):
  """
     Add new external_ref to meta node of an XML document.
  """
  if (meta is not None):
    ext_node = ET.SubElement(meta, "external", {"to_ref":ext_ref, "from_ref":from_ref})
    ret = ext_node

  else:
    ret = None

  return ret

#-------------------------------------------------------------------------------
def add_attachment(meta, to_path, ext, file):
  """
     Add new attachment to meta node of an XML document.
  """
  ret=None
  if (meta is not None):
    if len(xpath_list(meta,"attachment[@to_path='"+to_path+"']"))==0:
      att_node = ET.SubElement(meta, "attachment", {"to_path":to_path, "ext":ext, "file":file})
      ret = att_node

  return ret

#-------------------------------------------------------------------------------
def extend_to_connected(all_docs, ref_set):
  """
     Collect all connected references at any level.
  """
  new_ref_set = set() | ref_set
  for ref in ref_set:
    to_refs = xpath_list(all_docs, ".//external[@from_ref='"+ref+"']/@to_ref")
    new_ref_set |= set(to_refs)
    #from_refs = xpath_list(all_docs, ".//_meta/external[@to_ref='"+ref+"']/@from_ref")
    #new_ref_set |= set(from_refs)

  if (len(new_ref_set) != len(ref_set)):
    new_ref_set = extend_to_connected(all_docs, new_ref_set)

  return new_ref_set

#-------------------------------------------------------------------------------
def add_dict_as_xml(parent, a_dict):
  """
     Add to parent all nodes corresponding to tree structure contained in dict.
  """
  ret=parent
  if (parent is not None):
    for name0, value in a_dict.items():
      name = name0.lower()
      if isinstance(value, str) :     #simple string
        new = ET.SubElement(parent, name).text=value

      elif isinstance(value, list) :  #array
        for v in value:
          new = ET.SubElement(parent, name).text=v

      elif isinstance(value, dict) :  #dictionnary
        new = ET.SubElement(parent, name)
        add_dict_as_xml(new, value)

      else :
        new = ET.SubElement(parent, name)

  return ret


# 2016년 요일 찾기
# 2016년 1월 1일은 금요일
# SUN,MON,TUE,WED,THU,FRI,SAT
from datetime import datetime

def solution(a, b):
    date = '2016-{0}-{1}'.format(a, b) # 날짜
    datetime_date = datetime.strptime(date, '%Y-%m-%d') # 날짜의 타입을 datetime형으로 변경
    dateDict = {0: 'MON', 1:'TUE', 2:'WED', 3:'THU', 4:'FRI', 5:'SAT', 6:'SUN'}
    return dateDict[datetime_date.weekday()]

# 1년 중 첫 시작 요일을 알기 때문에
# 이전 달까지 모두 더하고, 일 수를 더한 후 7로 나눠주면 요일을 알 수 있다.
# 조건이 1년 내이고, 첫번째 날의 요일을 알기 때문에 이런 연산 방법이 더 적합할 것 같다.
def solution1(a, b):
    months = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    days = ['FRI', 'SAT', 'SUN', 'MON', 'TUE', 'WED', 'THU']
    return days[(sum(months[:a-1])+b-1)%7]

print(solution(5,24))


from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm

def register(request):
    if request.method =='POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            messages.success(request, f'User {username} has been successfully created')
            return redirect('all-goods')
    else:
        form = UserRegisterForm()
    return render(
        request,
        'users/registration.html',
        {'title': 'Registration page',
         'form': form,
         })


import pandas as pd
import lxml.html
import requests
import shelve
import os, sys
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()

if not os.path.exists('database'):
    os.mkdir('database')
elif not os.path.isdir('database'):
    os.remove('database')
    os.mkdir('database')

xlsx = 'database/Free+English+textbooks.xlsx'
xfile = pd.ExcelFile(xlsx)
df = xfile.parse()

books = shelve.open('database/serial')

class Book:

    PARENT = 'https://link.springer.com'

    def __init__(self, idx, title, edition, subject, url):

        self.title      = title.replace('/', '_')
        self.idx        = idx

        self.name       = f'{self.title}, {edition}'
        self.subject    = self._process(subject)
        self._image_url = None
        self._url       = url

        self.pdf        = None
        self.epub       = None

    def __repr__(self):
        return f'{self.idx}: {self.name}'

    def __eq__(self, other):
        return self.idx == other.idx

    def _process(self, subject):

        subject = subject.split(';')[0]

        book = self

        try:
            books[subject].append(book)
        except (KeyError, AttributeError):
            books[subject] = []
            books[subject].append(book)

        self._make_template(book, subject)

        return subject

    def _make_template(self, book, subject):

        path = os.path.join('templates', subject)

        if os.path.exists(path):
            return
        else:
            html = '''{% extends "base.html" %}
{% block content %}

<< BACK TO INDEX

{{ subject }} Books

    {% for book in books[subject] %}

{{ book.name }}

DOWNLOAD:

        {% if book.pdf %}
            PDF
        {% endif %}

        {% if book.epub %}
            EPUB
        {% endif %}

        {% if not book.pdf and not book.epub %}
            unavailable.
        {% endif %}

    {% endfor %}

{% endblock %}'''

            with open(path + '.html', 'w') as fhand:
                fhand.write(html)

    def _scrape(self):

        name = self.name.replace(' ', '_') + '.html'
        path = os.path.join('static', 'cache', name)

        if os.path.exists(path):
            with open(path, 'rb') as fhand:
                html = fhand.read()
                html = lxml.html.fromstring(html)
        else:
            response = requests.get(self._url)
            content  = response.content
            with open(path, 'wb') as fhand:
                fhand.write(content)
            html = lxml.html.fromstring(content)

        try:
            xpath, epub = self.__get_xpaths(html)
        except IndexError:
            print(f'Error: {self.idx} {self.name}'
                  ' server access point missing')
            return False

        else:
            self.__make_links(xpath, epub)

        finally:
            self.image = self.name.replace(' ', '_').replace('\\', '_') + '.jpeg'
            path       = os.path.join('static', 'images', self.image)
            if not os.path.exists(self.image):
                self.__set_image_url(html)
                try:
                    image = requests.get(self._image_url).content
                except:
                    image = ""
                finally:
                    with open(path, 'wb') as fhand:
                        fhand.write(image)

    def __get_xpaths(self, html):
        epub  = None
        xpath = html.xpath('//*[@id="main-content"]/article[1]/'
                           'div/div/div[2]/div/div/a')
        if not bool(xpath):
            xpath = html.xpath(
                '//*[@id="main-content"]/article[1]/div/div/div[2]/div[1]/a'
                )
            epub  = html.xpath(
                '//*[@id="main-content"]/article[1]/div/div/div[2]/div[2]/a'
                )
            epub = epub[0]
        xpath = xpath[0]
        return xpath, epub

    def __make_links(self, xpath, epub):
        stub     = xpath.get('href')
        self.pdf = __class__.PARENT + stub
        if epub is not None:
            stub      = epub.get('href')
            self.epub = __class__.PARENT + stub

    def __set_image_url(self, html):
        if self.pdf or self.epub:
            img_xpath = html.xpath(
                '//*[@id="main-content"]/article[1]/div/aside[1]/'
                'div/div/div/img'
            )
            img_xpath = None if not len(img_xpath) else img_xpath[0]
            self._image_url = img_xpath.get('src')
        else:
            self._image_url = ""

def load_data():

    for idx, row in df.iterrows():

        book = Book(idx,
                df['Book Title'].iloc[idx],
                df['Edition'].iloc[idx],
                df['Subject Classification'].iloc[idx],
                df['OpenURL'].iloc[idx])

        try:

            assert book in books[book.subject]
            logger.info(f' SKIPPING : {book.name}')
            continue

        except (KeyError, AssertionError) as init:

            subject = books[book.subject]
            book._scrape()
            subject.append(book)
            books[book.subject] = subject
            logger.info(f' SERIALIZED : {book.name}')

    else: books.close()


#!/usr/bin/python3
"""
    Started a Flask web application with these scripts
    the web apps was listed on 0.0.0.0, port 5000
    declare @app.teardown_appcontext and storage.close()
    with routes /cities_by_states: display a HTML page:
    in my route def option strict_slashes=False was used
"""
from flask import Flask, render_template
from models import storage
from models.state import State
from operator import getitem
app = Flask(__name__)

@app.route('/states_list', strict_slashes=False)
def list_states():
    """List all the states to the client"""
    states = storage.all(State).values()
    return render_template('7-states_list.html', states=states)

@app.route('/cities_by_states', strict_slashes=False)
def list_states_cities():
    """List all the states and its cities to the client"""
    states = storage.all(State).values()
    return render_template('8-cities_by_states.html', states=states)

@app.teardown_appcontext
def close_db(db):
    storage.close()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)


"""
Filename:     calc_volcello.py
Author:       Damien Irving, irving.damien@gmail.com
Description:  Calculate the CMIP5 volcello variable

"""

# Import general Python modules

import sys, os, pdb
import argparse
import numpy
import iris

# Import my modules

cwd = os.getcwd()
repo_dir = '/'
for directory in cwd.split('/')[1:]:
    repo_dir = os.path.join(repo_dir, directory)
    if directory == 'ocean-analysis':
        break

modules_dir = os.path.join(repo_dir, 'modules')
sys.path.append(modules_dir)

try:
    import general_io as gio
    import convenient_universal as uconv
    import spatial_weights
except ImportError:
    raise ImportError('Must run this script from anywhere within the ocean-analysis git repo')

# Define functions

def construct_volume_cube(volume_data, data_cube, global_atts):
    """Construct the new volume cube """

    volume_cube = data_cube.copy()
    volume_cube.data = volume_data
    volume_cube.standard_name = 'ocean_volume'
    volume_cube.long_name = 'Ocean Grid-Cell Volume'
    volume_cube.var_name = 'volcello'
    volume_cube.units = 'm3'
    volume_cube.cell_methods = ()
    if global_atts:
        volume_cube.attributes = global_atts

    return volume_cube

def main(inargs):
    """Run the program."""

    # Depth data
    data_cube = iris.load_cube(inargs.dummy_file, inargs.dummy_var)
    dim_coord_names = [coord.name() for coord in data_cube.dim_coords]
    aux_coord_names = [coord.name() for coord in data_cube.aux_coords]
    assert dim_coord_names[0] == 'time'
    depth_name = dim_coord_names[1]
    data_cube = data_cube[0, ::]
    data_cube.remove_coord('time')
    depth_data = spatial_weights.get_depth_array(data_cube, depth_name)
    # Area data
    if inargs.area_file:
        area_cube = iris.load_cube(inargs.area_file, 'cell_area')
        gio.check_global_ocean_area(area_cube.data.sum())
        area_data = uconv.broadcast_array(area_cube.data, [1, 2], depth_data.shape)
    else:
        area_data = spatial_weights.area_array(data_cube)

    volume_data = depth_data * area_data

    if inargs.sftof_file:
        sftof_cube = iris.load_cube(inargs.sftof_file)
        assert sftof_cube.data.max() == 100
        sftof_data = uconv.broadcast_array(sftof_cube.data, [1, 2], depth_data.shape)
        volume_data = volume_data * (sftof_data / 100.0)

    volume_data = numpy.ma.asarray(volume_data)
    data = numpy.ma.masked_invalid(data_cube.data)
    volume_data.mask = data.mask
    global_atts = area_cube.attributes if inargs.area_file else None
    volume_cube = construct_volume_cube(volume_data, data_cube, global_atts)
    volume_cube.attributes['history'] = gio.write_metadata()

    gio.check_global_ocean_volume(volume_cube.data.sum())

    iris.save(volume_cube, inargs.outfile)

if __name__ == '__main__':

    extra_info ="""
author:
  Damien Irving, irving.damien@gmail.com

"""

    description='Calculate the CMIP volcello variable'
    parser = argparse.ArgumentParser(description=description,
                                     epilog=extra_info,
                                     argument_default=argparse.SUPPRESS,
                                     formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument("dummy_file", type=str, help="Dummy file (for depth information)")
    parser.add_argument("dummy_var", type=str, help="Dummy variable")
    parser.add_argument("outfile", type=str, help="Output file name")

    parser.add_argument("--sftof_file", type=str, default=None,
                        help="Sea area fraction file name")
    parser.add_argument("--area_file", type=str, default=None,
                        help="Area file name (required for curvilinear grids, optional otherwise)")

    args = parser.parse_args()
    main(args)


import sys
import base64, time, datetime

callbacks = {
    'array': lambda x: [v.text for v in x],
    'dict': lambda x:
        dict((x[i].text, x[i+1].text) for i in range(0, len(x), 2)),
    'key': lambda x: x.text or "",
    'string': lambda x: x.text or "",
    'data': lambda x: base64.b64decode(x.text),
    'date': lambda x:
        datetime.datetime(
            *(time.strptime(x.text, "%Y-%m-%dT%H:%M:%SZ")[0:6])),
    'real': lambda x: float(x.text),
    'integer': lambda x: int(x.text),
    'true': lambda x: True,
    'false': lambda x: False,
}

def _xml_plist_parse(xml_input, _iterparse):
    parser = _iterparse(xml_input)
    for action, element in parser:
        callback = callbacks.get(element.tag)
        if callback:
            data = callback(element)
            element.clear()
            element.text = data
        elif element.tag != 'plist':
            raise IOError("unknown plist tag: %s" % element.tag)
    return parser.root[0].text

def parse_using_etree(xml_input):
    from xml.etree.ElementTree import iterparse as py_iterparse
    _xml_plist_parse(xml_input, py_iterparse)

def parse_using_cetree(xml_input):
    import xml.etree.cElementTree
    from xml.etree.cElementTree import iterparse as c_iterparse
    _xml_plist_parse(xml_input, c_iterparse)

if __name__ == '__main__':
    xmlin = open(sys.argv[1])
    try:
        assert parse_using_cetree(xmlin)
    finally:
        xmlin.close()


from fastapi import FastAPI, Request, HTTPException, status, Depends ,File, UploadFile
from fastapi.templating import Jinja2Templates
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.staticfiles import StaticFiles

from starlette.responses import HTMLResponse

from tortoise.contrib.fastapi import register_tortoise
from tortoise.signals import post_save
from tortoise import BaseDBAsyncClient

from typing import Optional, Type, List

from PIL import Image

import secrets
from datetime import datetime

from emails import *
from db_models import User, Business, Product
from pydentic_models import (
    user_pydenticIn,
    user_pydentic,
    business_pydentic,
    business_pydenticIn,
    product_pydenticIn,
    product_pydentic
)
from authentication import get_hashed_password, verify_token, token_generator

app = FastAPI()

templates = Jinja2Templates(directory='templates')

oauth2_scheme = OAuth2PasswordBearer(tokenUrl='token')

app.mount('/static', StaticFiles(directory='static'), name='static')

async def get_current_user(token: str=Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, config_credentials['SECRET'], algorithms=['HS256'])
        user = await User.get(id=payload.get('id'))
    except:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail='Invalid token',
            headers={'WWW-Authenticate': 'Bearer'}
        )

    return await user

@app.post('/products')
async def get_products(product: product_pydenticIn, user: user_pydentic=Depends(get_current_user)):
    product = product.dict(exclude_unset=True)

    if product['original_price'] > 0:
        product['percentage_discount'] = ((product['original_price'] - product['new_price']) / product['original_price']) * 100

        product_obj = await Product.create(**product, business=user)
        product_obj = await product_pydenticIn.from_tortoise_orm(product_obj)

        return {
            'status': 'OK',
            'data': product_obj
        }
    else:
        return {
            'status': 'ERROR'
        }

@app.get('/products')
async def get_product():
    response = await product_pydentic.from_queryset(Product.all())
    return {
            'status': 'OK',
            'data': response
        }

@app.get('/products/{id}')
async def get_product(id: int):
    product = await Product.get(id=id)
    business = await product.business
    owner = await business.owner

    response = await product_pydentic.from_queryset_single(Product.get(id=id))

    return {
            'status': 'OK',
            'data': {
                'product_details': product,
                'business_details': {
                    'name': business.name,
                    'city': business.city,
                    'region': business.region,
                    'description': business.description,
                    'logo': business.logo,
                    'owner_id': owner.id,
                    'email': owner.email,
                    'join_date': owner.join_date.strtime('%b %d %Y'),
                },
            }
        }

@app.delete('/products/{id}')
async def delete_product(id: int, user: user_pydentic=Depends(get_current_user)):
    product = await Product.get(id=id)
    business = await product.business
    owner = await business.owner

    if user == owner:
        product.delete()
        return {
            'status': 'OK'
        }

    return HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail='Invalid token',
        headers={'WWW-Authenticate': 'Bearer'}
    )

@app.post('/user/me')
async def user_login(user: user_pydenticIn=Depends(get_current_user)):
    business = await Business.get(owner=user)
    logo = business.logo
    logo_path = 'localhost:8000/static/images/' + logo

    return {
        'status': 'OK',
        'data': {
            'username': user.username,
            'email': user.email,
            'verified': user.is_verified,
            'join_date': user.join_date.strtime('%b %d %Y'),
            'logo': logo_path
        }
    }

@app.post('/token')
async def generate_token(request_form: OAuth2PasswordRequestForm = Depends()):
    token = await token_generator(request_form.username, request_form.password)
    return {'access_token': token,
            'token_type': 'bearer'}

@app.get('verification/', response_class=HTMLResponse)
async def email_verification(request: Request, token: str):
    user = await verify_token(token)

    if user and not user.is_verified:
        user.is_verified = True
        await user.save()
        return templates.TemplateResponse(
            'verification.html',
            {'request': request,
             'username': user.username},
        )
    raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail='Invalid token',
            headers={'WWW-Authenticate': 'Bearer'}
    )

@post_save(User)
async def create_business(sender: 'Type[User]', instance: User, created:bool,
    using_db: 'Optional[BaseDBAsyncClient]', updated_fields: List[str]) -> None :
    if created:
        business_obj = await Business.create(
            name=instance.username,
            owner = instance,
        )

        await business_pydentic.from_tortoise_orm(business_obj)
        await send_email([instance.email], instance)

@app.post('/registration')
async def user_registration(user: user_pydenticIn):
    user_info = user.dict(exclude_unset=True)
    user_info['password'] = get_hashed_password(user_info['password'])
    user_obj = await User.create(**user_info)
    new_user = await user_pydentic.from_tortoise_orm(user_obj)
    return {
        'status': 'OK',
        'data': f'Hello, {new_user.username}, thanks for your registration,  check your email'
    }

@app.get('/')
def index():
    return {'Message': 'Hello World!'}

@app.post('/uploadfile/profile')
async def create_upload_file(file: UploadFile=File(...), user: user_pydentic=Depends(get_current_user)):
    FILEPATH = './static/images/'
    filename = file.filename
    extension = filename.split('.')[1]

    if extension not in ['jpg', 'png']:
        return {
            'status': 'ERROR',
            'detail': 'File extension not allowed'
        }

    token_name = f'{secrets.token_hex(10)}.{extension}'
    generated_name = FILEPATH + token_name
    file_content = await file.read()

    with open(generated_name, 'wb') as file:
        file.write(file_content)

    img = Image.open(generated_name)
    img = img.resize(size=(200, 200))
    img.save(generated_name)

    file.close()

    business = await Business.get(owner=user)
    owner = await business.owner

    if owner == user:
        business.logo = token_name
        await business.save()

    else:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail='Not Authenticated to perform this action',
            headers={'WWW-Authenticate': 'Bearer'}
        )

    file_url = 'localhost:8000' + generated_name[1:]

    return {
        'status': 'OK',
        'filename': file_url
    }

@app.post('/uploadfile/product/{id}')
async def create_upload_file(id: int, file: UploadFile=File(...),
                                user: user_pydentic=Depends(get_current_user)):
    FILEPATH = './static/images/'
    filename = file.filename
    extension = filename.split('.')[1]

    if extension not in ['jpg', 'png']:
        return {
            'status': 'ERROR',
            'detail': 'File extension not allowed'
        }

    token_name = f'{secrets.token_hex(10)}.{extension}'
    generated_name = FILEPATH + token_name
    file_content = await file.read()

    with open(generated_name, 'wb') as file:
        file.write(file_content)

    img = Image.open(generated_name)
    img = img.resize(size=(200, 200))
    img.save(generated_name)

    file.close()

    product = await Product.get(id=id)
    business = await Product.business
    owner = await business.owner

    if owner == user:
        product.product_image = token_name
        await product.save()

    else:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail='Not Authenticated to perform this action',
            headers={'WWW-Authenticate': 'Bearer'}
        )

    file_url = 'localhost:8000' + generated_name[1:]

    return {
        'status': 'OK',
        'filename': file_url
    }

@app.put('/product/{id}')
async def update_product(id: int, update_info: product_pydenticIn, user: user_pydentic=Depends(get_current_user)):
    product = await Product.get(id=id)
    business = await product.business
    owner = await business.owner

    update_info = update_info.dict(exclude_unset=True)
    update_info['date_published'] = datetime.utcnow()

    if owner == user and update_info['original_price'] >= 0:
        update_info['percentage_discount'] = ((update_info['original_price'] - update_info['new_price']) / update_info['original_price']) * 100

        product = await product.update_from_dict(update_info)
        await product.save()
        response = await product_pydentic.from_tortoise_orm(product)

        return {
            'status': 'OK',
            'data': response
        }

    raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail='Not Authenticated to perform this action',
            headers={'WWW-Authenticate': 'Bearer'}
        )

@app.put('/business/{id}')
async def update_business(id: int, update_business: business_pydenticIn, user: user_pydentic=Depends(get_current_user)):
    update_business = update_business.dict()
    business = await Business.get(id=id)
    owner = await business.owner

    if user == owner:
        await business.update_from_dict(update_business)
        await business.save()
        response = await business_pydentic.from_tortoise_orm(business)

        return {
            'status': 'OK',
            'data': response
        }

    raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail='Not Authenticated to perform this action',
            headers={'WWW-Authenticate': 'Bearer'}
        )

register_tortoise(
    app,
    db_url='sqlite://database.sqlite3',
    modules={'models': ['db_models']},
    generate_schemas=True,
    add_exception_handlers=True,
)


import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
from .. import default_config
import numpy

class CustomViewBox(pg.ViewBox):
    def __init__(self, *args, **kwds):
        pg.ViewBox.__init__(self, *args, **kwds)
        self.StromDisplay=None
        self.ChannelNum=0
        self.ScaleBar = []
        self.ScaleSize = 0
        self.ScaleText = ''
        self.Window = []
        self.FreehandRoi = []
        self.DrawnRoi = []
        self.StormRegistrationChannel = -1
        self.ConfRegistrationChannel = -1
        self.DrawnRoi = []
        self.ConfocalOffset = [0, 0]
        self.StormMarkerRois = []
        self.ConfMarkerRois = []
        self.PanMode = default_config.viewer_input_mode
        self.ClickMode ='Norm'
        self.AffineTransform = []

    ## reimplement right-click to zoom out
    def mouseClickEvent(self, ev):
        if self.ClickMode == 'Reg':
            Current = self.mapToView(ev.pos())
            Marker= pg.ROI([0, 0])
            if len(self.StormMarkerRois)<3:
                self.StormMarkerRois.append(Marker)
                Marker.addFreeHandle([Current.x(),Current.y()])
                Handle=Marker.getHandles()[0]
                Handle.sides=4
                Handle.startAng=0
                Handle.buildPath()
                Handle.generateShape()
                self.StormDisplay.plot_widget.addItem(Marker)
            else:
                if len(self.ConfMarkerRois)<3:
                    self.ConfMarkerRois.append(Marker)
                    Marker.addFreeHandle([Current.x(),Current.y()])
                    self.StormDisplay.plot_widget.addItem(Marker)
                else:
                    self.ClickMode='Norm'

        else:
            pg.ViewBox.mouseClickEvent(self, ev)

    def SetRegistrationChannelStorm(self,StormChannelNum):
        self.StormRegistrationChannel=StormChannelNum

    def SetRegistrationChannelConf(self,ConfChannelNum):
        self.ConfRegistrationChannel=ConfChannelNum

    def mouseDragEvent(self, ev):
        if self.PanMode == 'Pan':
            pg.ViewBox.mouseDragEvent(self, ev)
        elif self.PanMode == 'Conf':
            cursorOffset = ev.screenPos() - ev.lastScreenPos()
            # scale to pixel coordinates
            XTrans = cursorOffset[0] * self.viewPixelSize()[0] / 8
            YTrans = cursorOffset[1] * self.viewPixelSize()[1] / 8
            self.ConfocalOffset = [self.ConfocalOffset[0] + YTrans, self.ConfocalOffset[1] + XTrans]

            for CN in range(4):
                if self.StormDisplay.DisplayedConfocalChannel[CN] != 0:
                    self.StormDisplay.DisplayedConfocalChannel[CN].translate(YTrans, XTrans)
            #move the registration markers if there are any:
            Scale=1000.0/self.StormDisplay.ConfocalSizeMultiplier
            for RoiInd in range(len(self.main_window.viewer.display.Viewbox.ConfMarkerRois)):
                Marker= pg.ROI([0, 0])
                OldPoints=self.ConfMarkerRois[RoiInd].getLocalHandlePositions()[0][1]
                self.StormDisplay.plot_widget.removeItem(self.ConfMarkerRois[RoiInd])
                self.ConfMarkerRois[RoiInd]=Marker
                Marker.addFreeHandle([OldPoints.x()+XTrans*Scale * self.StormDisplay.ConfocalMetaData['SizeX'],OldPoints.y()+YTrans*Scale * self.StormDisplay.ConfocalMetaData['SizeY']])
                self.StormDisplay.plot_widget.addItem(Marker)
            #calcualte correlation between confocal and storm channel

            #if event is finished display registration correlation
            if ev.isFinish():
                #if the displayed channels exist:
                if self.ConfRegistrationChannel!=-1 and self.StormRegistrationChannel!=-1:
                    #if the channels are displayed:
                    if self.StormDisplay.DisplayedConfocalChannel[self.ConfRegistrationChannel]!=0 and self.StormDisplay.DisplayedStormChannel[self.StormRegistrationChannel]!=0:
                        #maybe rescale the images if really slow;Or precalculate an image and just index from it
                        Im1=self.StormDisplay.DisplayedConfocalChannel[self.ConfRegistrationChannel]
                        Im2=self.StormDisplay.DisplayedStormChannel[self.StormRegistrationChannel]

                        Scale=1000.0/self.StormDisplay.ConfocalSizeMultiplier
                        Correlation=0
                        for ind in range(len(Im2.getData()[0])):
                            IndX=(int(Im2.getData()[0][ind])/(Scale * self.StormDisplay.ConfocalMetaData['SizeX']))-self.ConfocalOffset[1]
                            IndY=(int(Im2.getData()[1][ind])/(Scale * self.StormDisplay.ConfocalMetaData['SizeY']))-self.ConfocalOffset[0]
                            if IndX>-1 and IndX<Im1.image.shape[1] and IndY>-1 and IndY<Im1.image.shape[0]:
                                Correlation+=Im1.image[IndY,IndX]
                        Msg=self.main_window.status_bar.currentMessage()
                        Msg=str.split(str(Msg),' Correlation:')[0]
                        #find a possible norm of correlation
                        #mean might be a more representative value for normalization:numpy.mean(Im1.image)
                        MaxCorr=len(Im2.getData()[0])*Im1.image.max()
                        self.main_window.status_bar.showMessage(Msg+' Correlation: '+ str(float(Correlation)/float(MaxCorr)) )
                else:
                    Msg=self.main_window.status_bar.currentMessage()
                    Msg=str.split(str(Msg),' Correlation:')[0]
                    self.main_window.status_bar.showMessage(Msg+' Correlation: The selected channels are not displayed' )
            #print signal.correlate2d(Im1,Im2)
            if self.main_window.viewer.display.ConfocalSizeMultiplier==1:
                Scale=1000*self.main_window.viewer.display.ConfocalSizeMultiplier
            else:
                Scale=10*self.main_window.viewer.display.ConfocalSizeMultiplier
            self.main_window.doubleSpinBox_confocal_display_offset_x.setValue(
                int(self.ConfocalOffset[1] * Scale * self.main_window.viewer.display.ConfocalMetaData['SizeX']))
            self.main_window.doubleSpinBox_confocal_display_offset_y.setValue(
                int(self.ConfocalOffset[0] * Scale * self.main_window.viewer.display.ConfocalMetaData['SizeX']))
            ev.accept()
            pos = ev.pos()

            modifiers = QtGui.QApplication.keyboardModifiers()
            if modifiers == QtCore.Qt.ControlModifier and ev.button() == QtCore.Qt.LeftButton:
                if ev.isFinish():
                    # self.traj_widget.update_selection_infos()
                    self.rbScaleBox.hide()
                else:
                    rect_box = QtCore.QRectF(pg.Point(ev.buttonDownPos(ev.button())), pg.Point(pos))
                    rect_box = self.childGroup.mapRectFromParent(rect_box)
                    self.update_selection(rect_box)
                    self.traj_widget.update_selection_infos()
                    self.updateScaleBox(ev.buttonDownPos(), ev.pos())
        elif self.PanMode == 'Roi':
            Current = self.mapToView(ev.pos())
            Prev = self.mapToView(ev.lastPos())
            r1 = pg.QtGui.QGraphicsLineItem(Prev.x(), Prev.y(), Current.x(), Current.y())
            r1.setPen(pg.mkPen('w'))
            self.DrawnRoi.append(r1)
            self.addItem(r1)
            self.FreehandRoi.append(Current)
            # closing curve on finish
            if ev.isFinish():
                Current = self.mapToView(ev.buttonDownPos())
                Prev = self.mapToView(ev.pos())
                r1 = pg.QtGui.QGraphicsLineItem(Prev.x(), Prev.y(), Current.x(), Current.y())
                r1.setPen(pg.mkPen('w'))
                self.DrawnRoi.append(r1)
                self.addItem(r1)
                self.FreehandRoi.append(Current)

            ev.accept()
            pos = ev.pos()
            modifiers = QtGui.QApplication.keyboardModifiers()
            if modifiers == QtCore.Qt.ControlModifier and ev.button() == QtCore.Qt.LeftButton:
                if ev.isFinish():
                    # self.traj_widget.update_selection_infos()
                    self.rbScaleBox.hide()
                else:
                    rect_box = QtCore.QRectF(pg.Point(ev.buttonDownPos(ev.button())), pg.Point(pos))
                    rect_box = self.childGroup.mapRectFromParent(rect_box)
                    self.update_selection(rect_box)
                    self.traj_widget.update_selection_infos()
                    self.updateScaleBox(ev.buttonDownPos(), ev.pos())

    def deleteFreehandROI(self, roi):
        for r in self.DrawnRoi:
            self.removeItem(r)
        self.FreehandRoi = []
        self.DrawnRoi = []
        roi = None

    def deleteActiveContourROI(self, DrawnElements):
        for r in DrawnElements:
            self.removeItem(r)

    def deleteActiveContourROI3d(self, DrawnElements):
        for r in DrawnElements:
            self.removeItem(r)

    def deleteEllipseROI(self, roi):
        self.removeItem(roi)

    def updateMatrix(self, changed=None):
        # keep scale bar at same position
        if self.ScaleBar != []:
            ViewRange = self.viewRange()
            XLength = (ViewRange[0][1] - ViewRange[0][0]) * 0.05
            YLength = (ViewRange[1][1] - ViewRange[1][0]) * 0.05
            Xpos = ViewRange[0][0] + XLength
            Ypos = ViewRange[1][0] + YLength
            self.ScaleBar.clear()
            self.Window.removeItem(self.ScaleText)
            self.ScaleBar = self.Window.plot(x=[Xpos, Xpos + self.ScaleSize], y=[Ypos, Ypos], symbol='o')
            PosX = Xpos
            PosY = Ypos + YLength * 0.1
            self.ScaleText = pg.TextItem(text=str(self.ScaleSize) + ' nm', color=(200, 200, 200))
            self.Window.addItem(self.ScaleText)
            self.ScaleText.setPos(PosX, PosY)
        pg.ViewBox.updateMatrix(self, changed=None)

    def setScaleBar(self, ScaleBar, Window, Size, Text):
        self.ScaleBar = ScaleBar
        self.Window = Window
        self.ScaleSize = Size
        self.ScaleText = Text

    def deleteScaleBar(self):
        if self.ScaleBar != []:
            self.ScaleBar.clear()
            self.Window.removeItem(self.ScaleText)
            self.ScaleBar = []
            self.ScaleSize = 0
            self.ScaleText = ''

    def setWindow(self, Window):
        self.Window = Window

    def deleteConfocalImage(self):
        self.StromDisplay = None

    def setConfocalImage(self, StormDisplay, ChannelNum):
        self.StormDisplay = StormDisplay
        self.ChannelNum = ChannelNum


# load the example image and convert it to grayscale
import os

import cv2
import pytesseract

image = "example_01.jpg"
preprocess = "thresh"

image = cv2.imread(image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# check to see if we should apply thresholding to preprocess the
# image
if preprocess == "thresh":
    gray = cv2.threshold(gray, 0, 255,
                         cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# make a check to see if median blurring should be done to remove
# noise
elif preprocess == "blur":
    gray = cv2.medianBlur(gray, 3)

# write the grayscale image to disk as a temporary file so we can
# apply OCR to it
filename = "{}.png".format(os.getpid())
cv2.imwrite(filename, gray)

# load the image as a PIL/Pillow image, apply OCR, and then delete
# the temporary file

pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files (x86)\Tesseract-OCR\tesseract.exe'
text = pytesseract.image_to_string(gray)
os.remove(filename)
print(text)

# show the output images
cv2.imshow("Image", image)
cv2.imshow("Output", gray)
cv2.waitKey(0)


import cv2
import numpy as np
import argparse

def main():

    parser = argparse.ArgumentParser()

    parser.add_argument('-v','--video', type=str)
    parser.add_argument('-o','--output', type=str, default=None)

    args = parser.parse_args()

    vid = cv2.VideoCapture(args.video)

    width = int(vid.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(vid.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = int(vid.get(cv2.CAP_PROP_FPS))
    codec = cv2.VideoWriter_fourcc('a','v','c','1')
    out = cv2.VideoWriter(args.output, codec, fps, (width, height))

    while vid.isOpened():
        success, image = vid.read()
        if not success:
            print("ignoring empty video")
            break

        cv2.imshow("before", image)

        max_x, max_y, z = image.shape
        # print('image dimensions: x:', max_x, "by y:", max_y)

        # points are (y, x), thickness -1 for solid
        start_point = (154, 170)
        end_point = (500, 1200)
        # setting for 720x1280 (portrait) handstand video at ../add_noise/sleeves.mp4

        # draw red rectangle around area
        # line_color= (0, 0, 255)
        # line_thickness = 3
        # cv2.rectangle(image, start_point, end_point, line_color, line_thickness)

        # exclude area outside rectangle
        start_y, start_x = start_point
        end_y, end_x = end_point
        mask = np.zeros(image.shape[:2],np.uint8)
        mask[start_x:end_x,start_y:end_y] = 255
        image = cv2.bitwise_and(image,image,mask = mask)

        out.write(image)
        cv2.imshow("after", image)
        if cv2.waitKey(1) & 0xFF == 27:
            break
    vid.release()

if __name__ == "__main__":
    main()

# https://stackoverflow.com/questions/11492214/opencv-via-python-is-there-a-fast-way-to-zero-pixels-outside-a-set-of-rectangle
# img = cv2.imread('testimg.jpeg')
# start_x = 30
# start_y = 30
# end_x = 200
# end_y = 100

# mask = np.zeros(img.shape[:2],np.uint8)
# mask[start_y:start_y+end_y,start_x:start_x+end_x] = 255
# result = cv2.bitwise_and(img,img,mask = mask)
# cv2.imshow("result", result)


from django.shortcuts import render, redirect, get_object_or_404
from users.models import Profile
from .models import *
from addproject.models import *
from datetime import datetime
from django.shortcuts import render, redirect
from addproject.models import *
import json
import datetime
from django.http import JsonResponse
from addproject.models import *
from users import *
import sys, os
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
from addproject import models
from django.core.paginator import Paginator

def showmain(request):
    calendar = Calendar.objects.filter(writer=request.user, endday__contains=datetime.date.today(
    )).order_by('endday')  # 글을 작성한 유저의 캘린더 정보만 가져오겠다. 가까운 날짜 순으로 정렬
    projects = Project.objects.filter(followers=request.user)
    profile = Profile.objects.all()
    posts = Post.objects.all().order_by('-day')
    return render(request, 'mateapp/mainpage.html', {'calendar': calendar, 'projects':projects,'posts':posts, })

def showevent(request):
    if request.method == 'POST':
        date_num = json.loads(request.body)
        year = datetime.date.today().year
        month = datetime.date.today().month
        calendar = Calendar.objects.filter(writer=request.user, endday__contains=datetime.date(
            year, month, int(date_num))).order_by('endday')

        if calendar.count() == 1:
            c0_title = calendar[0].title
            c0_startday = calendar[0].startday
            c0_endday = calendar[0].endday
            c0_starttime = calendar[0].starttime
            c0_endtime = calendar[0].endtime
            c0_place = calendar[0].place
            c0_body = calendar[0].body
            c0_color = calendar[0].color
            c1_title = None
            c1_startday = None
            c1_endday = None
            c1_starttime = None
            c1_endtime = None
            c1_place = None
            c1_body = None
            c1_color = None
            context = {
            "status": "exist1",
            "title1": c0_title,
            "startday1": c0_startday,
            "endday1": c0_endday,
            "starttime1": c0_starttime,
            "endtime1": c0_endtime,
            "place1": c0_place,
            "body1" : c0_body,
            "color1" : c0_color,
            "title2": c1_title,
            "startday2": c1_startday,
            "endday2": c1_endday,
            "starttime2": c1_starttime,
            "endtime2": c1_endtime,
            "place2": c1_place,
            "body2" : c1_body,
            "color2" : c1_color,
        }
        elif calendar.count() >= 2:
            c0_title = calendar[0].title
            c0_startday = calendar[0].startday
            c0_endday = calendar[0].endday
            c0_starttime = calendar[0].starttime
            c0_endtime = calendar[0].endtime
            c0_place = calendar[0].place
            c0_body = calendar[0].body
            c0_color = calendar[0].color
            c1_title = calendar[1].title
            c1_startday = calendar[1].startday
            c1_endday = calendar[1].endday
            c1_starttime = calendar[1].starttime
            c1_endtime = calendar[1].endtime
            c1_place = calendar[1].place
            c1_body = calendar[1].body
            c1_color = calendar[1].color
            context = {
            "status": "exist2",
            "title1": c0_title,
            "startday1": c0_startday,
            "endday1": c0_endday,
            "starttime1": c0_starttime,
            "endtime1": c0_endtime,
            "place1": c0_place,
            "body1" : c0_body,
            "color1" : c0_color,
            "title2": c1_title,
            "startday2": c1_startday,
            "endday2": c1_endday,
            "starttime2": c1_starttime,
            "endtime2": c1_endtime,
            "place2": c1_place,
            "body2" : c1_body,
            "color2" : c1_color,
        }

        else:
            context = {"status": "null"}
        return JsonResponse(context)

def login(request):
    if request.user.is_authenticated:
        projects = Project.objects.all()
        return render(request, 'mateapp/mainpage.html', {'projects':projects})

    else:
        return render(request, 'account/login.html')

def create_schedule(request):
    projecttitles = Project.objects.filter(writer=request.user)
    if request.method == 'POST':
        new_schedule = Calendar()
        new_schedule.title = request.POST['title']
        new_schedule.writer = request.user
        new_schedule.body = request.POST['body']
        new_schedule.startday = request.POST.get('startday')
        new_schedule.endday = request.POST.get('endday')
        new_schedule.starttime = request.POST.get('starttime')
        new_schedule.endtime = request.POST.get('endtime')
        new_schedule.place = request.POST['place']
        new_schedule.save()
        return redirect('mateapp:calendar')
    else :
        new_schedule = Calendar.objects.all()
        return render(request, 'mateapp/create_schedule.html',{'new_schedule':new_schedule, 'projecttitles':projecttitles})

def calendar(request):
    calendar = Calendar.objects.filter(writer=request.user)  # 글을 작성한 유저의 캘린더 정보만 가져오겠다. 가까운 날짜 순으로 정렬
    calendars = Calendar.objects.filter(writer=request.user)
    schedules_list = []
    schedules = Calendar.objects.filter(writer=request.user)
    schedules_list.append(schedules)
    # 간트차트

    projects = Project.objects.all() # 모델을 전부 불러옴
    todos_list = [] # 빈리스트를 만듬 , 담아서 렌더링하는 경우가 많음
    todos = Calendar.objects.filter(writer=request.user)
    todos_list.append(todos) # 그 프로젝트의 등록된 투두를 불러와서 그걸 넣은거임
        # 보내고 싶은거 리스트로 보내서 장고나 뭐든 저런식으로 할 일이 많음
    #     # 알아두기
    return render(request, 'mateapp/calendar.html', {'projects':projects, 'todos_list':todos_list,'calendar':calendar, 'schedules_list':schedules_list, 'calendars':calendars})
    # 리스트 자체를 렌더링함

def timetable(request):
    if request.method == "POST":
        # Profile에서 요청받은 user의 정보만 불러옴
        profile = Profile.objects.get(user=request.user)
        profile.timetable = request.FILES.get('timetable')
        profile.save(update_fields=['timetable'])
    return redirect('mateapp:showmain')  # render 보단 redirect 가 낫다.

def project_detail(request, project_id):
    projects = Project.objects.filter(followers=request.user)
    project = Project.objects.get(pk=project_id)
    posts = Post.objects.all()
    post = Post.objects.filter(project=project)
    comment = Comment.objects.filter()
    page = int(request.GET.get('p',1))
    paginator = Paginator(post,4)
    boards = paginator.get_page(page)
    return render(request, 'mateapp/project.html', {'boards':boards, 'projects':projects,'project':project,'posts':posts, 'post':post})

# 포스트가 갖고 있는 숫자가 가장 높은걸 필터로 찾아서 오늘 날짜와 비교해서 출력함

# 게시물 CRUD

def create_post(request, project_id):
    projects = Project.objects.all()
    project = Project.objects.get(pk=project_id)
    posts = Post.objects.all()
    day = datetime.date.today()
    # post = Post.objects.get(project=project)
    if request.method == "POST":
        # project = Project.objects.get(title=project_title)
        post_title = request.POST['title']
        post_body = request.POST['body']
        Post.objects.create(title=post_title, user=request.user, project=project, body=post_body) # post는 세가지 필드가 있는데,
        # 어떤 모델이든간에 pk가 있어야함 Foreign key는 생략이 될 수가 없음, 일대다 관계일때 쓴다는건데
        #
    return redirect('mateapp:project_detail', project_id)
    # return render(request, 'mateapp/project.html', {'posts':posts,'projects':projects})

def create_comment(request, project_id, post_id):
    project = Project.objects.get(pk=project_id)
    post = Post.objects.get(pk=post_id)
    if request.method == "POST":
        post = get_object_or_404(Post,pk=post_id) #Post로 등록된 값이 잇으면 불러오고 없으면 404 출력시킴
        content = request.POST['content']
        file = request.FILES.get('file')
        Comment.objects.create(content=content, post=post, user=request.user) # 모델=뷰
    return redirect('mateapp:post_detail', project_id, post_id)
    # id는 식별값이기 때문에 무조건 존재하는 필드임

def post_detail(request, project_id, post_id):
    project = Project.objects.get(pk = project_id)
    post = Post.objects.get(pk = post_id)
    comments = Comment.objects.filter(post = post)
    page = int(request.GET.get('p',1))
    paginator = Paginator(comments,4)
    boards = paginator.get_page(page)
    return render(request, 'mateapp/project_post.html', {'boards':boards,'project':project, 'post':post, 'comments':comments})


from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

fcff_df = pd.read_excel('FCFF_analysis_filtered.xlsx', index_col=[0])
sgx_df = pd.read_csv('myData.csv', index_col=[1])

class StonksApp:
    def __init__(self, master):
        self.master = master
        master.title("StonkApp")

        # Initialise app variables
        self.idx = 0
        self.current_stock = fcff_df.index[self.idx]

        # Set up frame with charts and stats
        self.update_main_frame(self.generate_info_dict())

        # Set up frame for app buttons
        self.update_buttons_frame()

    def plot_chart(self, row: int, column: int, *args: pd.DataFrame, columnspan: int=2, title: str="", xlabel: str="", ylabel: str=""):
        """ Function to plot graphs on same chart from dataframes passed into the function as arguments

        :param row, column, and columnspan: variables for Tkinter grid styling
        :param title, xlablel, ylabel: variables for matplotlib chart
        :param *args: dataframes to be plotted onto chart
        """

        # Setting up of chart
        figure = plt.Figure(figsize=(6,5), dpi=70)
        ax = figure.add_subplot(111)
        line_graph = FigureCanvasTkAgg(figure, self.main_frame)
        line_graph.get_tk_widget().grid(row=row, column=column, columnspan=columnspan)

        # Plotting graphs
        for df in args:
            df.plot(kind='line', legend=True, ax=ax)

        # Chart styling
        ax.set_title(title)
        ax.set_xlabel(xlabel)
        ax.set_ylabel(ylabel)

    def generate_info_dict(self) -> dict:
        """ Function to generate a dictionary of info name and info value pairs to be displayed in app

        :return: info_dict
        """

        info_dict = {}

        # Show name of stock
        trading_code = self.current_stock.replace(".SI", "")
        self.trading_name = sgx_df.loc[trading_code, "Trading Name"]
        info_dict["Name"] = self.trading_name

        # Show sector of stock
        self.sector = sgx_df.loc[trading_code, "Sector"]
        info_dict["Sector"] = self.sector

        # Show wacc of stock
        self.wacc = fcff_df.loc[self.current_stock, "WACC"]
        info_dict["WACC"] = self.wacc

        # Show fcf of stock
        self.fcff = fcff_df.loc[self.current_stock, "FCFF"]
        self.shares_out = fcff_df.loc[self.current_stock, "Shares outstanding"]
        self.fcf = self.fcff/self.shares_out
        info_dict["FCF"] = self.fcf

        # Show fair value stat
        self.fair_value = fcff_df.loc[self.current_stock, "Fair value"]
        info_dict["Fair value"] = self.fair_value

        # Show percentage undervalued stat
        self.percentage_undervalued = fcff_df.loc[self.current_stock, "Percentage undervalued"]
        info_dict["Percentage undervalued"] = self.percentage_undervalued

        return info_dict

    def update_main_frame(self, info_dict: dict):
        """ Function to populate main frame """

        self.main_frame = Frame(self.master)
        self.main_frame.grid(row=0, column=0)

        # Update variables
        self.IS_df = pd.read_csv(f"Database/{self.current_stock}/IS.csv", index_col=[0])
        self.BS_df = pd.read_csv(f"Database/{self.current_stock}/BS.csv", index_col=[0])
        self.CF_df = pd.read_csv(f"Database/{self.current_stock}/CF.csv", index_col=[0])

        # Graphs to be plotted
        self.revenue_df = self.IS_df.loc["Revenue"]
        self.revenue_df = self.revenue_df.astype(float)

        self.operating_income_df = self.IS_df.loc["Operating Income"]
        self.operating_income_df=self.operating_income_df.astype(float)

        # Plot graph of revenue and operating income
        self.plot_chart(0, 0, self.revenue_df, self.operating_income_df, title="", xlabel="Year", ylabel="")

        # Display useful information
        for i, key in enumerate(info_dict):
            Label(self.main_frame, text= f"{key}: \n{info_dict[key]}", font='Helvetica 10').grid(row=(i//2)+1, column=i%2)

    def update_buttons_frame(self):
        """ Function to populate button frame with back, next, like, and watchlist buttons """
        """ Arranges layout of buttons """
        self.button_frame = Frame(self.master)

        # Back button
        self.back_button = Button(self.button_frame, text="Back", command=lambda: self.next(self.idx - 1))
        self.back_button.grid(row=0, column=0, pady="10", padx="10")

        # Next button
        self.next_button = Button(self.button_frame, text="Next", command=lambda: self.next(self.idx + 1))
        self.next_button.grid(row=0, column=1)

        # Like button
        self.like_button = Button(self.button_frame, text="Like", command=self.like)
        self.like_button.grid(row=1, column=0, pady="5", padx="10")

        # Toggle like button if stock is in watchlist
        self.toggle_like_button()

        # Watchlist button
        self.watchlist_button = Button(self.button_frame, text="Watchlist", command=self.watchlist)
        self.watchlist_button.grid(row=1, column=1, pady="5", padx="10")

        # Frame palcement
        self.button_frame.grid(row=1, column=0)

    def toggle_like_button(self):
        """ Toggle like button based on whether self.current_stock is in watchlist """

        with open("Cache/watchlist.txt", "r") as watchlist:
            lines = watchlist.readlines()
        if str(self.current_stock + '\n') in lines:
            self.like_button.config(relief="sunken")
        else:
            self.like_button.config(relief="raised")

    """ Functions to make buttons interactable """

    def next(self, idx):
        """ Function for next button to show next or previous stock """
        # Update variables
        self.idx = idx
        self.current_stock = fcff_df.index[self.idx]

        self.update_main_frame(self.generate_info_dict())

        # Toggle like button based on whether stock is in watchlist
        self.toggle_like_button()

    def like(self):
        """ Function for like button to add stock to watchlist """

        if self.like_button.config('relief')[-1] == 'sunken':
            self.like_button.config(relief="raised")
            with open("Cache/watchlist.txt", "r") as f:
                lines = f.readlines()
            with open("Cache/watchlist.txt", "w") as f:
                for line in lines:
                    if line.strip("\n") != self.current_stock:
                        f.write(line)
        else:
            with open("Cache/watchlist.txt", "a") as myfile:
                myfile.write(f"{self.current_stock}\n")
            self.like_button.config(relief="sunken")

    def watchlist(self):
        """ Function to see stocks in watchlist """

        def view_watchlist_stock(stock):
            """ Function for view button to look at selected stock """
            watchlist_window.destroy()
            self.master.deiconify()
            self.update_main_frame(self.generate_info_dict())
            self.current_stock = stock
            self.update_buttons_frame()

            #update self.idx to that of stock
            self.idx = list(fcff_df.index).index(stock)

        def delete_watchlist_stock(stock):
            """ Function for delete button to delete selected stock """

            with open("Cache/watchlist.txt", "r") as f:
                lines = f.readlines()
            with open("Cache/watchlist.txt", "w") as f:
                for line in lines:
                    if line.strip("\n") != stock:
                        f.write(line)

            idx = Lines.index(stock+'\n')
            labels[idx].destroy()
            view_buttons[idx].destroy()
            delete_buttons[idx].destroy()

            if len(lines) == 1:
                Label(second_frame, text='Watchlist is currently empty', font='Helvetica 10').grid(column=0)

            #untoggle like button on main window if stock on that window is removed from watchlist
            if stock == self.current_stock:
                self.update_buttons_frame()

        def search():
            """ Function for search button to search for a specified stock by its full ticker """
            search_ticker = search_entry.get()
            if search_ticker in fcff_df.index:
                view_watchlist_stock(search_ticker)

            else:
                messagebox.showerror("Error","Sorry the ticker you entered was not found within this spreadsheet")
                return

        def on_closing():
            """ Function to make main window reappear on closing of watchlist window """
            watchlist_window.destroy()
            self.master.deiconify()

        def back_to_main_button_command():
            """ Function to get back to main app when button is clicked"""
            watchlist_window.destroy()
            self.master.deiconify()

        # Create new window over current window
        self.master.withdraw()  # hide main window
        watchlist_window = Toplevel(self.master)
        watchlist_window.protocol("WM_DELETE_WINDOW", on_closing)  # make main window reappear on closing
        watchlist_window.title("Watchlist")
        watchlist_window.geometry("400x500")

        # Create search bar
        search_frame = Frame(watchlist_window)
        search_frame.pack()
        search_entry = Entry(search_frame)
        search_entry.pack(side=LEFT)
        search_button = Button(search_frame, text='Search', command=search)
        search_button.pack(side=LEFT)

        # Create a button to get back to main app
        back_to_main_button = Button(watchlist_window, text="Back to main app", command=back_to_main_button_command)
        back_to_main_button.pack(pady=5)

        ##### scroll button #####
        # Create A Main Frame
        main_frame = Frame(watchlist_window)
        main_frame.pack(fill=BOTH, expand=1)

        # Create A Canvas
        my_canvas = Canvas(main_frame)
        my_canvas.pack(side=LEFT, fill=BOTH, expand=1)

        # Add A Scrollbar To The Canvas
        my_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
        my_scrollbar.pack(side=RIGHT, fill=Y)

        # Configure The Canvas
        my_canvas.configure(yscrollcommand=my_scrollbar.set)
        my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))

        def _on_mouse_wheel(event):
            my_canvas.yview_scroll(-1 * int((event.delta / 120)), "units")

        my_canvas.bind_all("<MouseWheel>", _on_mouse_wheel)

        # Create ANOTHER Frame INSIDE the Canvas
        second_frame = Frame(my_canvas)

        # Add that New frame To a Window In The Canvas
        my_canvas.create_window((0,0), window=second_frame, anchor="nw")

        ##### end of scroll bar #####

        # Get list of stocks in watchlist
        file1 = open('Cache/watchlist.txt', 'r')
        Lines = file1.readlines()

        if len(Lines) == 0:
            Label(second_frame, text='Watchlist is currently empty', font='Helvetica 10').grid(column=0)

        labels = []     # Create empty lists to reference which ones to delete later on
        view_buttons = []
        delete_buttons = []

        # Display stocks in watchlist, with buttons to view or delete stock
        for i in range(len(Lines)):
            watchlist_stock_label = Label(second_frame, text=Lines[i], font='Helvetica 10')
            watchlist_stock_label.grid(row=i, column=0)
            watchlist_stock_button = Button(second_frame, text='View', command=lambda i=i: view_watchlist_stock(Lines[i].strip()))
            watchlist_stock_button.grid(row=i, column=1)
            delete_watchlist_stock_button = Button(second_frame, text='Remove', command=lambda i=i:delete_watchlist_stock(Lines[i].strip()))
            delete_watchlist_stock_button.grid(row=i, column=2)

            labels.append(watchlist_stock_label)
            view_buttons.append(watchlist_stock_button)
            delete_buttons.append(delete_watchlist_stock_button)

    def settings(self):
        pass

if __name__ == "__main__":
    root = Tk()
    StonksApp(root)
    root.mainloop()


import pytest
from sqlalchemy import create_engine

from rebrickable.data.database import Session
from rebrickable.data.models import *

models = [Color, Inventory, InventorySet,
          InventoryPart, Part, PartCategory, Set, Theme]

@pytest.fixture(scope='module')
def session():
    engine = create_engine('sqlite:///:memory:', echo=True)
    Session.configure(bind=engine)
    # You probably need to create some tables and
    # load some test data, do so here.

    # To create tables, you typically do:
    Base.metadata.create_all(engine)
    yield Session()
    Session.close_all()

@pytest.fixture
def objects():
    return [
        Color(id=1, name='black', rgb='123456', is_trans=True),
        Inventory(id=1, version=42, set_num='7189-1'),
        InventoryPart(inventory_id=1, part_num='3001', color_id=1, quantity=12),
        InventorySet(inventory_id=1, set_num='7189-1', quantity=1),
        Part(part_num='3001', name='Brick 2X4', part_cat_id=1),
        PartCategory(id=1, name='bricks'),
        Set(set_num='7189-1', name='Dumy Test', year=2015, theme_id=42, num_parts=12),
        Theme(id=42, name='Town', parent_id=None),
        Theme(id=43, name='Police', parent_id=42)
    ]

def test_models(session, objects):
    session.add_all(objects)

    session.commit()

    for obj in objects:
        session.refresh(obj)
        print(obj)


import copy

import matplotlib.colors as colors
import matplotlib.pyplot as plt
import nibabel as nib
import numpy as np
from matplotlib import cm

from util.util import info, crop_center, error, print_timestamped

different_colors = ["#FF0000", "#008000", "#0000FF", "#FFD700",  # Red, green, blue, gold
                    "#00BFFF", "#DDA0DD", "#808080", "#800000",  # Light blue, magenta, gray, maroon
                    "#808000", "#00FF00", "#FFFF00", "#800080",  # Olive, lime, yellow, purple
                    "#008080", "#000080"]  # Teal, navy

class PlotHandler:

    def __init__(self, args, options, complementary=False):
        self.output_data_folder = options.output_data_folder
        self.phase = options.phase  # 0 search, 1 train, 2 test
        self.prefix = options.prefix
        self.mapping_source = args.mapping_source
        self.mapping_target = args.mapping_target
        self.plot_names_dict = {}
        self.plot_names_dict['source'] = self.mapping_source
        self.plot_names_dict['target'] = self.mapping_target
        self.sliced = args.sliced
        self.chosen_slice = args.chosen_slice
        self.plot_only_results = args.plot_only_results
        self.nifti_image_extension = ".nii.gz"
        self.target_shape = (210, 180)
        if self.sliced:
            self.image_extension = ".png"
        else:
            self.image_extension = self.nifti_image_extension

        # Set plot folder
        base = self.output_data_folder / args.experiment_name
        if complementary:
            specific_name = "_complementary"
        else:
            specific_name = "_" + args.method + "_main" + str(args.main_clusters) + "_sub" + str(args.sub_clusters)

        if self.phase != 1:
            specific_name += "_" + str(args.postprocess)

        if self.phase == 0 or (self.phase == 2 and args.model_phase == "search"):
            self.plot_folder = base / (args.test_set + "_search" + specific_name)
        elif self.phase == 1:
            self.plot_folder = base / (self.prefix + specific_name)
        else:
            self.plot_folder = base / (args.test_set + specific_name)

        if self.phase != 1 or not self.plot_only_results:
            self.plot_folder.mkdir(parents=True, exist_ok=True)

        self.train_folder = None
        self.labels_folder = None

        info("The plots for the current run will be saved in " + str(base) + ".")
        if not args.plot_only_results and self.phase != 2:
            self.train_folder = self.plot_folder / "train"
            self.labels_folder = self.plot_folder / "labels"
            self.train_folder.mkdir(parents=True, exist_ok=True)
            self.labels_folder.mkdir(parents=True, exist_ok=True)

            print(
                "The plots of the training images for the current run will be saved in " + str(self.train_folder) + ".")
            print("The plots of the labels for the current run will be saved in " + str(self.labels_folder) + ".")

    def plot_reference(self, reference_mri, model_folder, mris_shape, affine, method, main, sub):
        plot_nifti(reference_mri,
                   model_folder / (
                           "lab_" + method + "_main" + str(main) + "_sub" + str(sub) + self.nifti_image_extension),
                   mris_shape,
                   affine)

    def plot_train(self, visuals, patient_name, mris_shape, affine):
        if not self.plot_only_results:
            for label, image in visuals.items():
                filename = self.train_folder / (patient_name + "_" + self.plot_names_dict[label] + self.image_extension)
                if self.sliced:
                    reshaped = image.reshape(mris_shape)
                    cropped = crop_center(reshaped, self.target_shape)
                    plot_image(cropped,
                               filename,
                               colormap=cm.get_cmap('gray'),
                               mris_shape=mris_shape,
                               plotbar=False)
                else:
                    reshaped = image.reshape(mris_shape)
                    cropped = crop_center(reshaped[:, :, self.chosen_slice], self.target_shape)
                    plot_image(cropped,
                               str(filename).split(".")[0] + ".png",
                               colormap=cm.get_cmap('gray'),
                               plotbar=False)
                    plot_nifti(image,
                               filename,
                               mris_shape,
                               affine=affine)

    def plot_results(self, visuals, patient_name, smoothing, mris_shape, affine):
        self.plot_names_dict['learned_target'] = self.mapping_target + "_learned"
        self.plot_names_dict['learned_target_smoothed'] = self.mapping_target + "_learned_" + smoothing
        for label, image in visuals.items():
            if 'truth' not in label:
                folder = self.plot_folder / patient_name
                folder.mkdir(parents=True, exist_ok=True)
                filename = folder / (patient_name + "_" + self.plot_names_dict[label] + self.image_extension)
                if self.sliced:
                    reshaped = image.reshape(mris_shape)
                    cropped = crop_center(reshaped, self.target_shape)
                    plot_image(cropped,
                               filename,
                               colormap=cm.get_cmap('gray'),
                               mris_shape=mris_shape,
                               plotbar=False)
                else:
                    reshaped = image.reshape(mris_shape)
                    cropped = crop_center(reshaped[:, :, self.chosen_slice], self.target_shape)
                    plot_image(cropped,
                               str(filename).split(".")[0] + ".png",
                               colormap=cm.get_cmap('gray'),
                               plotbar=False)
                    plot_nifti(image,
                               filename,
                               mris_shape,
                               affine=affine)

    def plot_shaded_labels(self, patient_name, labels1, labels2, method, main_clusters, mris_shape, affine):
        m1_filename = self.labels_folder / (
                patient_name + "_" + self.mapping_source + "_labels_" + method + self.image_extension)
        m2_filename = self.labels_folder / (
                patient_name + "_" + self.mapping_target + "_labels_" + method + self.image_extension)
        if self.sliced:
            reshaped1 = labels1.reshape(mris_shape)
            cropped1 = crop_center(reshaped1, self.target_shape)
            plot_image(cropped1,
                       m1_filename,
                       shaded_labels=1.0,
                       colormap=colormap_fusion(main_clusters),
                       mris_shape=mris_shape,
                       plotbar=False)
            reshaped2 = labels2.reshape(mris_shape)
            cropped2 = crop_center(reshaped2, self.target_shape)
            plot_image(cropped2,
                       m2_filename,
                       shaded_labels=1.0,
                       colormap=colormap_fusion(main_clusters),
                       mris_shape=mris_shape,
                       plotbar=False)
        else:
            reshaped1 = labels1.reshape(mris_shape)
            cropped1 = crop_center(reshaped1[:, :, self.chosen_slice], self.target_shape)
            plot_image(cropped1,
                       str(m1_filename).split(".")[0] + ".png",
                       shaded_labels=1.0,
                       colormap=colormap_fusion(main_clusters),
                       plotbar=False)
            reshaped2 = labels2.reshape(mris_shape)
            cropped2 = crop_center(reshaped2[:, :, self.chosen_slice], self.target_shape)
            plot_image(cropped2,
                       str(m2_filename).split(".")[0] + ".png",
                       shaded_labels=1.0,
                       colormap=colormap_fusion(main_clusters),
                       plotbar=False)
            plot_nifti(labels1,
                       m1_filename,
                       mris_shape,
                       affine=affine)
            plot_nifti(labels2,
                       m2_filename,
                       mris_shape,
                       affine=affine)

    def print_tumour(self, tumour, patient_name, mris_shape, affine):
        if not self.plot_only_results:
            folder = self.plot_folder / patient_name
            folder.mkdir(parents=True, exist_ok=True)
            filename = folder / (patient_name + "_truth_tumour" + self.image_extension)
            if self.sliced:
                plot_image(tumour,
                           filename,
                           mris_shape=mris_shape,
                           plotbar=False)
            else:
                reshaped = tumour.reshape(mris_shape)
                cropped = crop_center(reshaped[:, :, self.chosen_slice], self.target_shape)
                plot_image(cropped,
                           str(filename).split(".")[0] + ".png",
                           plotbar=False)
                plot_nifti(tumour,
                           filename,
                           mris_shape,
                           affine=affine)

def plot_image(image,
               filename,
               colormap=copy.copy(cm.get_cmap('viridis')),
               mris_shape=None,
               shaded_labels=None,
               one_int_bounds=False,
               plotbar=True,
               white_bg=False,
               verbose=True):
    if plotbar:
        res_size1 = 6
        res_size2 = 5
    else:
        res_size1 = res_size2 = 5
    fig = plt.figure(figsize=(res_size1, res_size2), dpi=300)
    # ax = plt.gca()
    if len(image.shape) == 1:
        if mris_shape is not None:
            image = image.reshape(mris_shape)
        else:
            error("The image cannot be reshaped and showed with imshow")
    elif len(image.shape) > 2:
        error("The image has a shape greater than 2. You might have forgotten to slice it.")
    image = np.rot90(image, k=-1)
    image = np.flip(image, axis=1)
    if shaded_labels is None:
        max_lin = np.max(image)
        bounds = None
    else:
        n_clusters = int(colormap.N / 256)
        max_lin = shaded_labels
        bounds = np.linspace(0, max_lin, n_clusters + 1)
    if one_int_bounds and max_lin < 15:
        bounds = range(int(max_lin) + 1)
    min_val = np.min(image) + 0.1e-10
    if min_val > max_lin:
        min_val = max_lin
    if colormap != cm.get_cmap('gray'):
        colormap.set_under('w')
    plt.axis('off')
    plt.xticks([])
    plt.yticks([])
    sc = plt.imshow(image,
                    cmap=colormap,
                    vmin=min_val,
                    vmax=max_lin)
    if plotbar:
        # divider = make_axes_locatable(ax)
        # cax = divider.append_axes("right", size="5%", pad=0.05)
        cax = None
        plt.colorbar(sc, cax=cax, ticks=bounds)

    plt.savefig(filename, bbox_inches='tight', transparent=not white_bg)
    if verbose:
        print_timestamped("Saved in " + str(filename))
    plt.close(fig)

def plot_nifti(image, filename, mris_shape=None, affine=None, verbose=True):
    if affine is None:
        affine = np.array([[-1., 0., 0., -0.],
                           [0., -1., 0., 239.],
                           [0., 0., 1., 0.],
                           [0., 0., 0., 1.]])
    if len(image.shape) == 1:
        if mris_shape is not None:
            image = image.reshape(mris_shape)
        else:
            error("The image cannot be reshaped, please add the shape.")
    new_nifti = nib.Nifti1Image(image, affine=affine)
    nib.save(new_nifti, filename)
    if verbose:
        print_timestamped("Saved in " + str(filename))

def colormap_fusion(n_clusters):
    if n_clusters > len(different_colors):
        error("The number of clusters is greater than the available size of colours.")
    stacked_colors = []
    for i in range(n_clusters):
        colormap = shaded_color_map(different_colors[i])
        linspace_colormap = colormap(np.linspace(0.20, 1, 256))
        stacked_colors.append(linspace_colormap)

    newcolors = np.vstack(stacked_colors)
    return colors.ListedColormap(newcolors)

def full_colormap_fusion(n_clusters):
    if n_clusters > len(different_colors):
        error("The number of clusters is greater than the available size of colours.")
    return colors.ListedColormap(different_colors[:n_clusters])

def shaded_color_map(rgb_color):
    return colors.LinearSegmentedColormap.from_list("", ["white", rgb_color])