from .count_analysis import *
from datetime import timedelta
from django.shortcuts import render, redirect
import json
import pdb

# TODO
"""

2. Clean up the following debug
- DEBUG tags

8. Set flags to prevent further processing upon upload
"""

def index(request):
    # UPON SUCCESSFUL LOCAL FILE UPLOAD
    if request.method == "POST" and request.FILES['WhatsAppFile']:
        # RESET SERVER SIDE COOKIE STORING fileContentsList
        request.session.flush()

        # CLEAR EXISTING METRICS
        CountAnalysis.clearMetrics()

        # PERFORM FILE READ AND PARSE INTO LIST OF STRINGS
        fileContentsList = readFile(request.FILES['WhatsAppFile'])

        # PLACE THE LIST OF PARSED STRINGS INTO fileContentsList
        request.session['fileContentsList'] = fileContentsList

        # REDIRECT TO METRICS PAGE
        return redirect('metrics/')

    # SERVE THE HOMEPAGE AS USUAL
    return render(request, 'whatsanalyzer/homepage.html')

def charts(request):
    senderOne = CountAnalysis.senderList[0]
    senderTwo = CountAnalysis.senderList[1]
    senderOneDates = CountAnalysis.senderOneTimeStamp
    senderTwoDates = CountAnalysis.senderTwoTimeStamp
    senderOneReplyTimingInMinutes = CountAnalysis.senderOneReplyTimingInMinutes
    senderTwoReplyTimingInMinutes = CountAnalysis.senderTwoReplyTimingInMinutes

    # Custom date formatter for x-axis
    def xAxisFormatter(date):
        # Convert to GMT+8 timezone
        date += timedelta(hours=8)
        return date.strftime("%d %b %Y, %H:%M")

    # Custom hour formatter for y-axis
    def yAxisFormatter(replyTimeInMinutes):
        return round(replyTimeInMinutes / 60, 2)

    return render(request, 'whatsanalyzer/charts.html',
                  {'senderOne': json.dumps(senderOne),
                   'senderTwo': json.dumps(senderTwo),
                   'senderOneDates': json.dumps(senderOneDates, indent=4, sort_keys=True, default=xAxisFormatter),
                   'senderOneReplyTimingInMinutes': list(map(yAxisFormatter, senderOneReplyTimingInMinutes)),
                   'senderTwoDates': json.dumps(senderTwoDates, indent=4, sort_keys=True, default=xAxisFormatter),
                   'senderTwoReplyTimingInMinutes': list(map(yAxisFormatter, senderTwoReplyTimingInMinutes))})

def metrics(request):

    # FROM CLOUD
    if request.method == "POST":
        # CountAnalysis.setInitialized(False)
        # CountAnalysis.clearMetrics()
        # MessageStorage.clearMessageList()
        textFile = request.POST.get('textFile')
        fileContentsList = textFile.split('\n')
        setMetrics(fileContentsList)
        print("CLOUD EXECUTED")

    # FROM LOCAL PC
    else:
        try:
            # CALCULATE THE METRICS FOR DISPLAY AND REMOVE IT
            fileContentsList = request.session.pop('fileContentsList')
            setMetrics(fileContentsList)
            print("LOCAL EXECUTED")

        # TRIGGERED BY ABSENCE OF 'fileContentsList' IN THE SESSION KEYS
        except KeyError:
            pass

    # RETRIEVE METRICS FROM CountAnalysis
    if CountAnalysis.getInitialized():
        s1 = CountAnalysis.senderList[0]
        s2 = CountAnalysis.senderList[1]
        s1TotalMsg = CountAnalysis.senderOneTotalMessages
        s1TotalWords = CountAnalysis.senderOneTotalWords
        s1WPM = CountAnalysis.senderOneWordsPerMsg
        s1AvgReply = sum(CountAnalysis.senderOneReplyTimingInMinutes) / len(CountAnalysis.senderOneReplyTimingInMinutes)
        s2TotalMsg = CountAnalysis.senderTwoTotalMessages
        s2TotalWords = CountAnalysis.senderTwoTotalWords
        s2WPM = CountAnalysis.senderTwoWordsPerMsg
        s2AvgReply = sum(CountAnalysis.senderTwoReplyTimingInMinutes) / len(CountAnalysis.senderTwoReplyTimingInMinutes)

        # TOTAL MESSAGES
        if s1TotalMsg > s2TotalMsg:
            # LARGE DIFF
            if s1TotalMsg / s2TotalMsg > 1.25:
                leftMessageText = f"Dear {s1}, you're obviously the more active person in this particular conversation, " \
                    f"sending over {'%d' % ((s1TotalMsg / s2TotalMsg) * 100 - 100)}% more texts since the start of your conversation!"
                rightMessageText = f"Dear {s2}, guess you're more a quiet person, but that's okay! {s1} is definitely a really " \
                    f"good friend and chat buddy you'll always wanna keep!"

            # SMALL DIFF
            else:
                leftMessageText = f"Mhm, {s1}, you both have sent nearly the same " \
                    f"number of texts to each other so far!"
                rightMessageText = f"{s2}, seems like you're both equally invested in the conversation, that's good!"

        else:
            # LARGE DIFF
            if s2TotalMsg / s1TotalMsg > 1.25:
                leftMessageText = f"Dear {s1}, guess you're more a quiet person, but that's okay! {s2} is definitely a really " \
                    f"good friend and chat buddy you'll always wanna keep around!"

                rightMessageText = f"Dear {s2}, you're obviously the more active person in this particular conversation, " \
                    f"sending over {'%.2f' % (s2TotalMsg / s1TotalMsg)} times more texts since the start of your conversation!"
            # SMALL DIFF
            else:
                leftMessageText = f"Well, {s1}, you've both sent around the same number of texts so far!"

                rightMessageText = f"Ahh, {s2}, all your texts are getting responded to, so no worries there!"

        # TOTAL WORDS
        if s1TotalWords > s2TotalWords:
            # LARGE DIFF
            if s1TotalWords / s2TotalWords > 1.25:
                leftWordsText = f"You're quite a chatty person, {s1}, I hope {s2} likes it! Well, do keep up " \
                    f"this excellent chemistry you guys have!"
                rightWordsText = f"On behalf of {s1}, thanks for being such a great listener, {s2}, and try not to let {s1} " \
                    f"dominate the conversation ;)"
            # SMALL DIFF
            else:
                leftWordsText = f"Well, {s1}, you're both equally chatty! So nothing you need to worry about here!"
                rightWordsText = f"Great, {s2}, you're both equally invested in your conversations, so keep that up!"
        else:
            # LARGE DIFF
            if s2TotalWords / s1TotalWords > 1.25:
                leftWordsText = f"On behalf of {s2}, thanks for being such a great listener, {s1}, and try not to let {s2} " \
                    f"dominate the conversation ;)"
                rightWordsText = f"You're quite a chatty person, {s2}! Do keep up this excellent chemistry you guys have!"

            # SMALL DIFF
            else:
                leftWordsText = f"Well, {s1}, both of you are equally chatty, so keep that up!"
                rightWordsText = f"Mhmm {s2}, great to see that you're both equally chatty!"

        # WPM
        if s1WPM > s2WPM:
            # LARGE DIFF
            if s1WPM / s2WPM > 1.25:
                leftWPMText = f"My my, {s1}, your texts are turning into essays!"

                rightWPMText = f"Well, {s2}, {s1} sure loves talking to you!"

            # SMALL DIFF
            else:
                leftWPMText = f"Ahh, {s1}, seems like you're both equally engaged in the conversation, so do keep that up!!"
                rightWPMText = f"Dear {s2}, seems like you're both equally engaged in the conversation, so do keep that up!!"
        else:
            # LARGE DIFF
            if s2WPM / s1WPM > 1.25:
                leftWPMText = f"Well, {s1}, {s2} sure loves talking to you!"

                rightWPMText = f"My my, {s2}, your texts are turning into essays!"

            # SMALL DIFF
            else:
                leftWPMText = f"Dear {s1}, seems like you're both equally engaged in the conversation, so do keep that up!!"
                rightWPMText = f"Ahh {s2}, seems like you're both equally engaged in the conversation, so do keep that up!!"

        # REPLY TIMINGS
        if s1AvgReply > s2AvgReply:
            # LARGE DIFF
            if s1AvgReply / s2AvgReply > 1.25:
                leftReplyText = f"You're a really busy person, {s1}! That's all right, but do make some time to respond to your texts :)"
                rightReplyText = f"{s2}, you must hate waiting for {s1}'s texts, don't you? But do give {s1} some space!"
            # SMALL DIFF
            else:
                leftReplyText = f"Seems like quite a healthy interaction going on here, nothing to worry about there, {s1}!"
                rightReplyText = f"Seems like quite a healthy interaction going on here, nothing to worry about there, {s2}!"
        else:
            # LARGE DIFF
            if s2AvgReply / s1AvgReply > 1.25:
                leftReplyText = f"{s1}, you must hate waiting for {s2}'s texts, don't you?  But do give {s2} some space!"
                rightReplyText = f"You're a really busy person, {s2}! That's all right, but do make some time to respond to your texts :)"

            # SMALL DIFF
            else:
                leftReplyText = f"Seems like quite a healthy interaction going on here, nothing to worry about there, {s1}!"
                rightReplyText = f"Seems like quite a healthy interaction going on here, nothing to worry about there, {s2}!"

        # PLACEHOLDERS
        chattierPerson = s1 if s1WPM > s2WPM else s2
        chattierWPM = s1WPM if s1WPM > s2WPM else s2WPM
        slowerPerson = s1 if s1AvgReply > s2AvgReply else s2
        slowerPercent = int(s1AvgReply / s2AvgReply * 100 - 100) if s1AvgReply > s2AvgReply else int(
            s2AvgReply / s1AvgReply * 100 - 100)

        # SERVE HTTP RESPONSE
        return render(request, 'whatsanalyzer/metrics.html', {'s1TotalMsg': s1TotalMsg,
                                                              's1TotalWords': s1TotalWords,
                                                              's1WPM': s1WPM,
                                                              's2TotalMsg': s2TotalMsg,
                                                              's2TotalWords': s2TotalWords,
                                                              's2WPM': s2WPM,
                                                              's1AvgReply': round(s1AvgReply / 60, 1),
                                                              's2AvgReply': round(s2AvgReply / 60, 1),
                                                              'leftMessageText': leftMessageText,
                                                              'rightMessageText': rightMessageText,
                                                              'leftWordsText': leftWordsText,
                                                              'rightWordsText': rightWordsText,
                                                              'leftWPMText': leftWPMText,
                                                              'rightWPMText': rightWPMText,
                                                              'leftReplyText': leftReplyText,
                                                              'rightReplyText': rightReplyText,
                                                              'chattierPerson': chattierPerson,
                                                              'chattierWPM': chattierWPM,
                                                              'slowerPerson': slowerPerson,
                                                              'slowerPercent': slowerPercent})
    else:
        return index(request)

def setMetrics(fileContentsList):
    # CLEAR HISTORY OF METRICS
    MessageStorage.clearMessageList()
    CountAnalysis.clearMetrics()

    # PERFORM ANALYSIS
    CountAnalysis.extractMessages(fileContentsList)
    CountAnalysis.calculateMetrics()

    # SET INITIALIZED IN COUNT_ANALYSIS
    CountAnalysis.setInitialized(True)

def readFile(uploadedFile):
    fileContents = uploadedFile.read().decode('utf-8')
    fileContentsList = fileContents.split('\n')
    return fileContentsList

def stash(request):
    return render(request, 'whatsanalyzer/stash.html')


import argparse
import torch
from torch.autograd import Variable
import numpy as np
import time, math
import scipy.io as sio
import matplotlib.pyplot as plt

parser = argparse.ArgumentParser(description="PyTorch LapSRN Demo")
parser.add_argument("--cuda", action="store_true", help="use cuda?")
parser.add_argument("--model", default="model/model_epoch_100.pth", type=str, help="model path")
parser.add_argument("--image", default="butterfly_GT", type=str, help="image name")
parser.add_argument("--scale", default=4, type=int, help="scale factor, Default: 4")

def PSNR(pred, gt, shave_border=0):
    height, width = pred.shape[:2]
    pred = pred[shave_border:height - shave_border, shave_border:width - shave_border]
    gt = gt[shave_border:height - shave_border, shave_border:width - shave_border]
    imdff = pred - gt
    rmse = math.sqrt(np.mean(imdff ** 2))
    if rmse == 0:
        return 100
    return 20 * math.log10(255.0 / rmse)

opt = parser.parse_args()
cuda = opt.cuda

if cuda and not torch.cuda.is_available():
    raise Exception("No GPU found, please run without --cuda")

model = torch.load(opt.model)["model"]

im_gt_y = sio.loadmat("Set5/" + opt.image + ".mat")['im_gt_y']
im_b_y = sio.loadmat("Set5/" + opt.image + ".mat")['im_b_y']
im_l_y = sio.loadmat("Set5/" + opt.image + ".mat")['im_l_y']

im_gt_y = im_gt_y.astype(float)
im_b_y = im_b_y.astype(float)
im_l_y = im_l_y.astype(float)

psnr_bicubic = PSNR(im_gt_y, im_b_y,shave_border=opt.scale)

im_input = im_l_y/255.

im_input = Variable(torch.from_numpy(im_input).float()).view(1, -1, im_input.shape[0], im_input.shape[1])

if cuda:
    model = model.cuda()
    im_input = im_input.cuda()
else:
    model = model.cpu()

start_time = time.time()
HR_2x, HR_4x = model(im_input)
elapsed_time = time.time() - start_time

HR_4x = HR_4x.cpu()

im_h_y = HR_4x.data[0].numpy().astype(np.float32)

im_h_y = im_h_y*255.
im_h_y[im_h_y<0] = 0
im_h_y[im_h_y>255.] = 255.
im_h_y = im_h_y[0,:,:]

psnr_predicted = PSNR(im_gt_y, im_h_y,shave_border=opt.scale)

print("Scale=",opt.scale)
print("PSNR_predicted=", psnr_predicted)
print("PSNR_bicubic=", psnr_bicubic)
print("It takes {}s for processing".format(elapsed_time))

fig = plt.figure()
ax = plt.subplot("131")
ax.imshow(im_gt_y, cmap='gray')
ax.set_title("GT")

ax = plt.subplot("132")
ax.imshow(im_b_y, cmap='gray')
ax.set_title("Input(Bicubic)")

ax = plt.subplot("133")
ax.imshow(im_h_y, cmap='gray')
ax.set_title("Output(LapSRN)")
plt.show()


import pywhatkit

print("Bienvenido")

print("Escribe el tema que quieres investigar")
tema = str(input())

print("En cuentas lineas quieres la invetigacion?:")

lineas = int(input())

pywhatkit.info(tema, lines = lineas)

"Nota: tiene error con las palabras (xbox, google, auronplay), pronto se solucionara"


""" Local record system implementation
"""
import json
import random
import string

from requests import Response
from rest_framework import status

from core_linked_records_app.components.local_id.models import LocalId
from core_linked_records_app.system.local_id import api as local_id_system_api
from core_linked_records_app.utils.providers import AbstractIdProvider
from core_main_app.commons import exceptions

class LocalIdProvider(AbstractIdProvider):
    """Local Id Provider"""

    messages = {
        "success": "Successful operation",
        "not_found": "Record not found",
        "already_exist": "Record already exists",
    }

    def __init__(self, provider_name):
        super().__init__(provider_name, None)

    @staticmethod
    def _generate_id(length_id=16):
        return "".join(
            random.choice(string.ascii_uppercase + string.digits)
            for _ in range(length_id)
        )

    def is_id_already_used(self, record):
        """is_id_already_used
        Args:
            record

        Returns:
        """
        return (
            json.loads(self.get(record).content)["message"]
            == self.messages["success"]
        )

    def get(self, record):
        """get

        Args:
            record:

        Returns:
        """

        response = Response()

        record_url = f"{self.provider_lookup_url}/{record}"

        try:
            local_id_system_api.get_by_name(record)
            response.status_code = status.HTTP_200_OK
            response._content = json.dumps(
                {
                    "message": self.messages["success"],
                    "record": record,
                    "url": record_url,
                }
            )
        except exceptions.DoesNotExist:
            response.status_code = status.HTTP_404_NOT_FOUND
            response._content = json.dumps(
                {
                    "message": self.messages["not_found"],
                    "record": record,
                    "url": record_url,
                }
            )

        return response

    def create(self, prefix, record=None):
        """create

        Args:
            prefix:
            record:

        Returns:
        """

        if record is None:
            # FIXME: duplicate code with core_main_registry_app
            # Create new record randomly
            record = self._generate_id()

            # While the record exists, retry creation of record
            while self.is_id_already_used(f"{prefix}/{record}"):
                record = self._generate_id()

        record = f"{prefix}/{record}"
        record_url = f"{self.provider_lookup_url}/{record}"

        response = Response()
        response_content = {
            "record": record,
            "url": record_url,
        }

        try:
            record_object = LocalId(record_name=record)

            local_id_system_api.insert(record_object)

            response.status_code = status.HTTP_201_CREATED
            response_content["message"] = self.messages["success"]
        except exceptions.NotUniqueError:
            response.status_code = status.HTTP_409_CONFLICT
            response_content["message"] = self.messages["already_exist"]

        response._content = json.dumps(response_content)
        return response

    def update(self, record):
        """update

        Args:
            record:

        Returns:
        """
        self.create(record)

        record_url = f"{self.provider_lookup_url}/{record}"

        response = Response()
        response._content = json.dumps(
            {
                "record": record,
                "message": self.messages["success"],
                "url": record_url,
            }
        )

        return response

    def delete(self, record):
        """delete

        Args:
            record:

        Returns:
        """
        response = Response()

        record_url = f"{self.provider_lookup_url}/{record}"

        try:
            record_object = local_id_system_api.get_by_name(record)
            local_id_system_api.delete(record_object)

            response.status_code = status.HTTP_200_OK
            response._content = json.dumps(
                {
                    "record": record,
                    "message": self.messages["success"],
                    "url": record_url,
                }
            )
        except exceptions.DoesNotExist:
            response.status_code = status.HTTP_404_NOT_FOUND
            response._content = json.dumps(
                {
                    "record": record,
                    "message": self.messages["not_found"],
                    "url": record_url,
                }
            )

        return response


import os
import csv
import functools

AMPERSAND = '&'
LESS_THAN = '<'
MORE_THAN = '>'
APOSTROFE = '’'
ASTERISCO = '•'

ROLES = ['HQ', 'Troops', 'Elites', 'Fast Attack', 'Heavy Support', 'Flyer', 'Dedicated Transport', 'No Force Org Slot']

ANGELS_OF_DEATH = 'And They Shall Know No Fear, Bolter Discipline, Combat Doctrines'

KEY_WORDS_IN_RULES = ['When', 'Re-roll', 'During', 'If', 're-roll', 'Ballistic',
                      'target', 'suffer', 'to hit', 'Each', 'select', 'Instead', 'shooting', 'For the purposes',
                      'Each time', 'gain', 'controls', 'Roll', 'firing', 'You can', 'This model', 'cannot', 'must',
                      'subtract', 'rolls', 'The first time', 'roll', 'In addition', 'Models', ' If', 'can be included',
                      'preventing', 'After', 'At the start', 'each', 'Command phase', 'if', 'added', 'Can', 'Cannot',
                      'counts', 'number of dice', 'characteristic', 'model']

RULE_BOOKS = ['Codex:', 'Psychic Awakening']

MODELS_STAT = ['M', 'WS', 'BS', 'S', 'T', 'W', 'A', 'Ld', 'Save'], ['Inv', 'FNP']
WEAPONS_STATS = ['Range', 'Type', 'S', 'AP', 'D', 'Abilities']
PSY_POW_STATS = ['Psychic Power', 'Warp Charge', 'Range', 'Details']
PSY_MODEL_ABILITY_STATS = ['Cast', 'Deny', 'Powers Known', 'Other']

class ParseFromHtml:
    extension = '.txt'
    book_references_list = ['Psychic Awakening']
    serial_No = 10000
    path = os.getcwd()
    address = './ParsedData'
    own_dir = '/ready_data_'
    full_path = f'{address}{own_dir}'

    def __init__(self, battle_scribe_html_file):

        # Army data:
        self.name = None
        self.pts = None
        self.CP = 0
        self.battle_type = None
        self.detachment = None
        self.faction = None
        self.subfaction = None
        self.codex = None

        self.amount_of_units = None

        self.roles = []
        self.units = []
        self.psychic_powers = []
        self.army_rules = {}  # all of them
        self.warlord = None

        # METHODS TO CONSTRUCT OBJECT, this data is only useful for program insides
        self.file = battle_scribe_html_file
        self.raw_data_text = []  # all the html with out code in txt
        self.general_rules_text = []
        self.army_rules_names = []
        self.army_rules_list = []
        self.general_rules_text = list(zip(self.army_rules_names, self.army_rules_list))
        for rule in self.general_rules_text:
            self.army_rules[rule[0]] = rule[1]
        self.all_unit_chunks = []

        # system
        self.start_system()

        # all parse data organise in:
        self.create_general_dir()
        self.create_army_dir()

        # empty memory
        self.general_rules_text = []
        self.army_rules_names = []
        self.raw_units_text = []
        self.raw_psy_text = []

        #  todo: -weapon, stats ( + record, csv, sqlite)

    def __repr__(self):
        if not self.psychic_powers:
            self.psychic_powers = None
        return f"""
Army Name: {self.name}
Army Points: {self.pts}
Army Detachment: {self.detachment}
Army Faction: {self.faction}
Army CPs: {self.CP}
Army Battle Type: {self.battle_type}
Army Sub-Faction: {self.subfaction}
Army Rules: {self.army_rules}
Army Roles: {self.roles}
Army Amount of Units: {self.amount_of_units}
Army Psychic Powers: {self.psychic_powers}
Army Units: {self.units}"""

    def start_system(self):
        self.open_file_to_data()
        self.cut_first_part()  # up to HQ lines
        self.cut_last_part()
        self.cut_mid_size_tags_lines()
        self.mark_start_of_unit()
        self.deal_with_small_tags()

        self.erase_Categories_Configuration_lines()
        self.erase_Detachment_Command_Cost_lines()
        self.erase_configuration_CP_line()
        self.erase_blank_lines()
        self.emplace_more_les_than_signs()
        self.emplace_ampersand()
        self.emplace_apostrofe()
        self.emplace_asterisco()

        self.populate_general_rules_data()  # separates general rules and units

        self.get_army_name()
        self.get_army_pts()
        self.get_detachment()
        self.get_faction()
        self.get_CP()
        self.get_battle_type()
        self.get_first_line_rule()
        self.get_sub_faction()
        self.get_faction_ability()

        self.create_general_dir()
        self.create_army_dir()
        self.record_raw_data_in_txt()

        self.erase_pages_and_useless_data()
        self.fix_army_rules_names()
        self.get_the_rest_of_the_general_rules()
        self.make_general_rules_text_pair_odd_lines()
        self.get_the_damned_rules()
        self.record_rules_in_csv()
        # end of rules block

        self.get_psychic_powers()
        self.parse_psy_powers()
        self.record_psypow_in_csv()
        # end of psy pow block

        self.clean_unit_pages_references()
        self.how_many_each_roles_in_army()

        self.test()

    def create_general_dir(self):
        if not os.path.exists(f'{self.address}'):
            os.mkdir(f'{self.address}')

    def create_army_dir(self):
        address = f'{self.full_path}{self.name}'
        if not os.path.exists(address):
            os.mkdir(address)
        self.address = address

    # PREPARE RAW DATA BlOCK
    def open_file_to_data(self):
        with open(self.file, 'r') as file:
            data = file.readlines()

        for line in data:
            if line != '\n':
                self.raw_data_text.append(line.strip())

    def record_raw_data_in_txt(self):
        """inner method: prepare the html in txt format to be parsed"""

        filename = self.name.strip()
        name = filename + self.extension
        if not os.path.exists(f'{self.address}'):
            self.address = f'{self.address}/plain_text_data_{filename}'
            os.mkdir(self.address)

        with open(f'{self.address}/{name}', 'w') as file:
            for line in self.raw_data_text:
                file.writelines(line + '\n')

    def cut_first_part(self):  # ok 28.11.2021
        """inner method: get rid off all css lines"""

        index = 0
        data = None
        for item in self.raw_data_text:
            if item == '':
                data = self.raw_data_text[index + 1:]

            index += 1
        self.raw_data_text = data

    def cut_last_part(self):  # ok 28.11.2021
        """inner method: erases the "Created with Battlescribe" line"""

        end_index = 0
        for line in self.raw_data_text:
            if 'Created with' in line:
                end_index = self.raw_data_text.index(line)

        data = self.raw_data_text[:end_index]
        self.raw_data_text = data

    def cut_mid_size_tags_lines(self):  # ok 28.11.2021
        """inner method: erases the lines under lenth 12"""

        data = []

        for line in self.raw_data_text:
            if len(line) > 12:
                data.append(line)
        self.raw_data_text = data

    def mark_start_of_unit(self):  # ok 28.11.2021
        """inner method: add lines with marks where the units starts"""

        stop_str = '
'
        new_raw_data = []
        index = 0

        for line in self.raw_data_text:

            if index < len(self.raw_data_text) - 1:
                next_line = self.raw_data_text[index + 1]
                if stop_str in line and 'PL' in next_line and 'Battle Size [' not in next_line:
                    line = '__START OF A UNIT__'
            new_raw_data.append(line)
            index += 1
        self.raw_data_text = new_raw_data

    def deal_with_small_tags(self):  # ok 28.11.2021
        """inner method: exchanges table tags for spaces"""

        raw_data = []
        for line in self.raw_data_text:
            if '	' in line:
                line = line.replace('	', ' ')
            if '	' in line:
                line = line.replace('	', ' ')
            new_line = self.erase_tags_from_line(line)
            raw_data.append(new_line)

        self.raw_data_text = raw_data

    def erase_Categories_Configuration_lines(self):
        """inner method: erases lines that contain the word "Categories" & "Configuration" """

        raw_data = []
        for line in self.raw_data_text:
            if 'Categories: Configuration' not in line:
                raw_data.append(line)
        self.raw_data_text = raw_data

    def erase_Detachment_Command_Cost_lines(self):
        """inner method: erases lines that contain the word "Detachment Command Cost" """

        raw_data = []
        for line in self.raw_data_text:
            if 'Detachment Command Cost' not in line:
                raw_data.append(line)
        self.raw_data_text = raw_data

    def erase_configuration_CP_line(self):
        """inner method: erases lines that contain the word "configuration CP" """
        raw_data = []
        for line in self.raw_data_text:
            if 'Configuration [' not in line:
                raw_data.append(line)
        self.raw_data_text = raw_data

    def erase_blank_lines(self, data=None):
        """inner method: erases lines that contain newline signs and empty strs """
        if not data:
            data = self.raw_data_text
        raw_data = []
        for line in data:
            new_line = line.split('\n')
            if new_line[0]:
                raw_data.append(new_line[0])
        self.raw_data_text = raw_data

    def emplace_more_les_than_signs(self):
        """inner method: replaces code for right simbols"""

        new_data = []
        for line in self.raw_data_text:
            if MORE_THAN in line and LESS_THAN in line:
                line = self.more_les_than(line)

            new_data.append(line)
        self.raw_data_text = new_data

    def emplace_ampersand(self):
        """inner method: replaces code for right simbols"""

        new_data = []
        for line in self.raw_data_text:
            if AMPERSAND in line:
                line = self.ampersand(line)

            new_data.append(line)
        self.raw_data_text = new_data

    def emplace_apostrofe(self):
        """inner method: replaces code for right simbols"""

        new_data = []
        for line in self.raw_data_text:
            if APOSTROFE in line:
                line = self.apostrofe(line)

            new_data.append(line)
        self.raw_data_text = new_data

    def emplace_asterisco(self):
        """inner method: replaces code for right simbols"""

        new_data = []
        for line in self.raw_data_text:
            if ASTERISCO in line:
                # print(line)
                line = self.asterisco(line)
                # print(line)
            new_data.append(line)
        self.raw_data_text = new_data

    def populate_general_rules_data(self):
        """inner method: splits the raw text in general rules and unit rules to be parsed separately
        it modifies the raw text file"""

        index = 0
        new_raw_data = []

        while index < len(self.raw_data_text) - 1:
            line = self.raw_data_text[index]
            # get the top rules
            self.general_rules_text.append(line)

            # get the units data
            if 'No Force Org Slot [' in line:

                while 'Force Rules' not in line and index < len(self.raw_data_text) - 1:
                    line = self.raw_data_text[index]
                    if 'Force Rules' in line:
                        break
                    new_raw_data.append(line)
                    index += 1

            if 'HQ [' in line:
                while 'Force Rules' not in line and index < len(self.raw_data_text) - 1:
                    line = self.raw_data_text[index]
                    # self.raw_units_text.append(line)
                    if 'Force Rules' in line:
                        break
                    new_raw_data.append(line)

                    index += 1
            index += 1

        self.raw_units_text = new_raw_data

        # check if resume
        is_resume = False
        for line in self.raw_data_text:
            if 'Force Rules' in line or 'Selection Rules' in line:
                is_resume = True

        if is_resume:
            index = len(self.raw_data_text) - 1
            while index > 0:
                line = self.raw_data_text[index]
                if 'Force Rules' in line or 'Selection Rules' in line:
                    butt = self.raw_data_text[index:]
                    self.general_rules_text.extend(butt)
                    break
                index -= 1

    # GENERAL DATA GETTERS
    def get_army_name(self):  # ok 29.11.2021
        line = self.general_rules_text[0]
        self.name = line.split(' (')[0]
        self.general_rules_text.remove(line)

    def get_army_pts(self):  # ok 29.11.2021
        line = self.general_rules_text[0]
        pts_text = ''
        if 'CP, ' in line:
            a = line.split('CP, ')[1]
            pts_text = a.split(']')[0]

        elif ', , ' in line:
            a = line.split(', , ')[1]
            pts_text = a.split('pts]')[0]

        no_coma_pts = ''
        for char in pts_text:
            if char.isdigit():
                no_coma_pts += char
        self.pts = int(no_coma_pts)

    def get_detachment(self):  # ok 29.11.2022
        for line in self.general_rules_text:
            if 'Detachment' in line:
                self.detachment = line.split(' Detachment')[0]
                break

    def get_faction(self):
        for line in self.general_rules_text:

            if 'Detachment' in line and '(' in line:
                a = line.split('(')[1]
                faction = a.split(')')[0]
                self.faction = faction
                self.general_rules_text.remove(line)
                break

    def get_CP(self):  # ok 29.11.2021
        for line in self.general_rules_text:

            if 'Battle Size' in line:

                if '[' in line:
                    cp = line.split('[')[1]
                    cp = cp.split('CP]')[0]
                    self.CP = int(cp)
                    self.general_rules_text.remove(line)
                    break
                else:
                    print('CPs not specified in list')
                    print('I asume is 18CP')
                    self.CP = 18
                    self.general_rules_text.remove(line)
                    break

        for line in self.general_rules_text:
            if 'Configuration [' in line:
                cp = line.split('[')[1]
                cp = cp.split('CP]')[0]
                self.CP = int(cp)
                self.general_rules_text.remove(line)
                break

    def get_battle_type(self):  # ok 29.11.2021
        for line in self.general_rules_text:

            if 'Selection' in line and 'PL' in line:
                if '. ' in line:
                    a = line.split('. ')[1]
                    battle_size = a.split(' (')[0]
                    self.battle_type = battle_size
                    self.general_rules_text.remove(line)

    def get_first_line_rule(self):
        for line in self.general_rules_text:
            if 'Rules: ' in line:
                rules = line.split('Rules: ')[1]
                self.army_rules_names.append(rules)
                self.general_rules_text.remove(line)

    def get_sub_faction(self):
        subfaction_name = ''
        subfaction = ''

        for line in self.general_rules_text:

            if ' Choice' in line:
                subfaction_name = line.split(' Choice')[0]
                self.general_rules_text.remove(line)
                break
            if 'Selector' in line:
                subfaction_name = line.split('Selector')[0]
                subfaction_name = subfaction_name.split('**')[1]
                self.general_rules_text.remove(line)
                break
            else:
                subfaction_name = line.strip()
                self.general_rules_text.remove(line)
                break

        if ' / ' in subfaction_name:
            subfaction_name = subfaction_name.split(' / ')[0]

        for line in self.general_rules_text:
            if 'Selections:' in line:
                if 'Custom' in line:
                    subfaction = self.fix_succesor_chapter_order(line)
                    self.general_rules_text.remove(line)
                    break
                if 'Selections:' in line:
                    subfaction = line.split('Selections: ')[1]
                    self.general_rules_text.remove(line)
                    break

        self.subfaction = (subfaction_name, subfaction)

    def get_faction_ability(self):
        for line in self.general_rules_text:
            if 'Abilities: ' in line:
                faction_ability = line.split('Abilities: ')[1]
                if ', ' in faction_ability:
                    faction_ability = faction_ability.split(', ')
                    for item in faction_ability:
                        self.army_rules_names.append(item)
                    self.general_rules_text.remove(line)
                    break
                else:
                    self.army_rules_names.append(faction_ability)
                    self.general_rules_text.remove(line)
                    break

    @staticmethod
    def fix_succesor_chapter_order(line):
        """inner method: in the case of the marines, the sucessor chapter rules are not ordered, this function fixes
        that """
        new_line = ''
        arrange = []
        line_list = line.split(':')[1]
        line_list = line_list.split(',')

        # put succesor first in list
        for item in line_list:
            if 'Successor' in item:
                arrange.append(item)

        for item in line_list:
            if ' Custom Chapter' in item:
                arrange.append(item)

        for item in arrange:
            if item != arrange[-1]:
                new_line += item + ', '
            else:
                new_line += item
        return new_line

    def erase_pages_and_useless_data(self):
        """inner method: find rest of useless data to erase"""
        for line in self.general_rules_text:
            if self.condition1(line) and self.condition2(line):
                self.general_rules_text.remove(line)

        for line in self.general_rules_text:
            if line == 'Description':
                self.general_rules_text.remove(line)

        for line in self.general_rules_text:
            if 'Selection Rules' in line:
                self.general_rules_text.remove(line)

        for line in self.general_rules_text:
            if 'Force Rules' in line:
                self.general_rules_text.remove(line)

        for line in self.general_rules_text:
            if 'Codex:' in line:
                step1 = line.split('Codex: ')[1]
                self.codex = step1.split(' p')[0]
                self.general_rules_text.remove(line)

        for line in self.general_rules_text:
            for book_reference in self.book_references_list:
                if book_reference in line:
                    self.general_rules_text.remove(line)

        for line in self.general_rules_text:
            if 'This unit has the following abilities:' in line:
                self.general_rules_text.remove(line)

    @staticmethod
    def condition1(line):
        is_useless = False
        useless_data = ['[', '(', 'Abilities', 'Description', 'Selection Rules']
        for item in useless_data:
            if item in line:
                is_useless = True
        return is_useless

    @staticmethod
    def condition2(line):
        return len(line) < 40

    def fix_army_rules_names(self):

        new_list = []
        for item in self.army_rules_names:
            if ',' in item:
                subitems = item.split(', ')
                for sub_item in subitems:
                    new_list.append(sub_item.strip())
            else:
                new_list.append(item.strip())

        self.army_rules_names = new_list

    def get_the_rest_of_the_general_rules(self):

        for line in self.general_rules_text:
            if ':' in line and len(line) < 40:
                rule = line.split(':')[0]
                if rule not in self.army_rules_names:
                    self.army_rules_names.append(rule)

    def make_general_rules_text_pair_odd_lines(self):

        index = 0
        max_index = len(self.general_rules_text) - 1

        while index < max_index:
            current_line = self.general_rules_text[index]
            if 'Angels of Death' in current_line:
                self.general_rules_text.insert(index + 1, ANGELS_OF_DEATH)
            elif len(current_line) < 35:
                next_line = self.general_rules_text[index + 1]
                if len(next_line) < 35:
                    self.general_rules_text.insert(index + 1, 'NO DATA')
                    index += 1
            index += 1

    def get_the_damned_rules(self):

        self.general_rules_text = self.set_in_same_order(self.general_rules_text)

        new_dict = {}
        new_list = []
        index = 0
        max_index = len(self.general_rules_text) - 1
        key = ''
        value = ''

        while index < max_index:
            line = self.general_rules_text[index]
            if len(line) < 35:  # found new key
                if key and value:  # last key value is over, needs to record
                    new_dict[key] = value
                    new_list.append([key, value])
                # get new key
                key = line
                # reset value
                if value:
                    value = ''
                index += 1
            else:
                value += line
                index += 1
            if index == max_index:  # ends the text
                if not value:
                    value += self.general_rules_text[-1]
                new_dict[key] = value
                new_list.append([key, value])

        self.army_rules = new_dict
        self.army_rules_list = new_list

    def record_rules_in_csv(self):

        file_name = f'general rules {self.name}'
        fieldnames = ['Ability', 'Description']

        with open(f'{self.full_path}{self.name}/{file_name}.csv', 'w') as f:
            writer = csv.writer(f)

            writer.writerow(fieldnames)

            for item in self.army_rules_list:
                writer.writerow(item)

    # TOOLS
    @staticmethod
    def is_new_line_sign(line):
        if '\n' in line:
            print(line.count('\n'))

    @staticmethod
    def erase_tags_from_line(line):

        index = 0
        new_line = ''
        while index < len(line):
            if line[index] == '<':
                while line[index] != '>':
                    index += 1
            else:
                if line[index] != '>':
                    new_line += line[index]
                index += 1

        return new_line

    @staticmethod
    def set_in_same_order(some_list):

        unique_items = []

        for item in some_list:
            if item not in unique_items:
                unique_items.append(item)

        return unique_items

    @staticmethod
    def ampersand(line):
        """this is made to deal with 0ne str at the time"""

        if type(line) == list:
            for item in line:
                if AMPERSAND in item:
                    new_line = item.replace(AMPERSAND, '&')
                    return new_line
        elif type(line) == str:
            if AMPERSAND in line:
                new_line = line.replace(AMPERSAND, '&')
                return new_line

        return AMPERSAND in line

    @staticmethod
    def more_les_than(line):

        if type(line) == list:
            for item in line:
                if LESS_THAN in item and MORE_THAN in item:
                    new_line = item.replace(LESS_THAN, '<')
                    new_line = new_line.replace(MORE_THAN, '>')
                    return new_line
        elif type(line) == str:
            if LESS_THAN in line and MORE_THAN in line:
                new_line = line.replace(LESS_THAN, '<')
                new_line = new_line.replace(MORE_THAN, '>')
                return new_line

        return LESS_THAN in line and MORE_THAN in line

    @staticmethod
    def apostrofe(line):

        if type(line) == list:
            for item in line:
                if APOSTROFE in item:
                    new_line = item.replace(APOSTROFE, "'")
                    return new_line
        elif type(line) == str:
            if APOSTROFE in line:
                new_line = line.replace(APOSTROFE, "'")
                return new_line

        return APOSTROFE in line

    @staticmethod
    def asterisco(line):

        if type(line) == list:
            for item in line:
                if ASTERISCO in item:
                    new_line = item.replace(ASTERISCO, "*")
                    return new_line
        elif type(line) == str:
            if ASTERISCO in line:
                new_line = line.replace(ASTERISCO, "*")
                return new_line

        return ASTERISCO in line

    @staticmethod
    def is_item_of_list_in_line(line, list_of_items):

        for item in list_of_items:
            if item in line:
                return True
        return False

    @staticmethod
    def wich_item_is_in_line(line, list_of_items, return_index=False):

        if return_index:
            index = 0
            for item in list_of_items:
                if item in line:
                    return list_of_items.index(item)
                index += 1
            return None  # it returns None automatically

        else:
            for item in list_of_items:
                if item in line:
                    return item
            return None

    @staticmethod
    def move_next_line(index, data):

        index += 1
        line = data[index]
        return index, line

    @staticmethod
    def is_quote_or_dash(line):

        is_quote_or_dash = False

        if line[0].isdigit():
            for char in line:
                if char == '"':
                    is_quote_or_dash = True
                    break

        elif line[0] == '-':
            is_quote_or_dash = True

        return is_quote_or_dash

    # PREPARE UNIT TEXT DATA
    def clean_unit_pages_references(self):
        for line in self.raw_units_text:
            if ':' in line:
                for book in RULE_BOOKS:
                    if book in line:
                        self.raw_units_text.remove(line)

    def points_per_role(self):

        pts_list = []
        data = self.raw_units_text

        for line in data:
            is_role = self.is_item_of_list_in_line(line, ROLES)
            if is_role and ' [' in line:
                # role = self.wich_item_is_in_line(line, ROLES)
                step = line.split(', ')[1]
                pts = step.split('pts')[0]
                pts_list.append(pts)
                self.raw_units_text.remove(line)

        return pts_list

    def how_many_each_roles_in_army(self):
        index = 0
        max_index = len(self.raw_units_text) - 1
        new_list = []
        amounts = []
        data = self.raw_units_text
        line = data[index]
        role = None

        while index < max_index:
            is_role = self.wich_item_is_in_line(line, ROLES)

            if is_role and ' [' in line:  # found a role
                index, line = self.move_next_line(index, data)
                role = is_role

            elif '__START OF A UNIT__' in line and index < max_index:
                index, line = self.move_next_line(index, data)
                if role:
                    # print(role)
                    new_list.append(role)

            else:
                if index < max_index:
                    index, line = self.move_next_line(index, data)

        all_roles = self.set_in_same_order(new_list)

        for item in all_roles:
            amount = new_list.count(item)
            amounts.append(amount)

        self.amount_of_units = functools.reduce(lambda a, b: a + b, amounts)
        pts = self.points_per_role()
        roles_amount_pts = list(zip(all_roles, amounts, pts))
        self.roles = roles_amount_pts

        # create a stop '__START OF A UNIT__' for unit chunk parse
        self.raw_units_text.append('__START OF A UNIT__')

    # Psy powers parse and clean up
    def get_psychic_powers(self):

        # for line in self.raw_units_text:
        #     print(line)

        data = self.raw_units_text
        index = 0
        max_index = len(data) - 1
        new_raw_text = []
        psy_chunk = []

        while index < max_index:
            line = data[index]
            if 'Warp Charge Range Details' in line:
                index, line = self.move_next_line(index, data)
                while 'Cast Deny Powers Known Other' not in line:
                    if line == 'Psyker':
                        index, line = self.move_next_line(index, data)
                    else:
                        if 'If' in line:
                            begining = line[:6]
                            index_start = line.index('If')
                            line = begining + line[index_start:]
                        psy_chunk.append(line)
                        psy_chunk = self.set_in_same_order(psy_chunk)
                        index, line = self.move_next_line(index, data)
            else:
                new_raw_text.append(line)
                index += 1

        self.raw_psy_text = psy_chunk

    def parse_psy_powers(self):
        data = self.raw_psy_text
        index = 0
        max_index = len(data) - 1
        details = None
        name = None
        warp_charge = None
        pow_range = None

        # for line in self.raw_psy_text:
        #     print(line)

        while index < max_index:
            line = data[index]
            if index % 2 == 1:
                value = line
                # print(value)
                warp_charge = value[0]
                pow_range = value[2:5]
                pow_range = pow_range.split('"')[0]
                details = value[6:]
                index += 1
            else:
                if ')' in line:
                    line = line.split(') ')[1]
                if ' (' in line:
                    line = line.split(' (')[0]
                name = line
                index += 1
            if name and warp_charge and warp_charge and pow_range and details:
                self.psychic_powers.append([name, warp_charge, pow_range, details])
                name = None
                warp_charge = None
                pow_range = None
                details = None

        self.raw_psy_text = []

    def record_psypow_in_csv(self):
        # todo:
        file_name = f'Psy Powers {self.name}'
        fieldnames = PSY_POW_STATS

        with open(f'{self.address}/{file_name}.csv', 'w') as f:
            writer = csv.writer(f)

            writer.writerow(fieldnames)

            for item in self.psychic_powers:
                writer.writerow(item)

    def parse_weapon_stats_record_in_csv(self):
        for item in self.all_unit_chunks:
            print(item)
        pass

    def parse_models_stats_record_in_csv(self):
        pass

    # unit parse and clean up
    # def build_a_unit(self):
    #
    #     # TODO: find all inf build model by model first
    #
    #     fieldrole = ''
    #     name = ''
    #     models = []  # ['sgt', 'marine', 'marine' ...]
    #     categories = []  # list of names of categories
    #     equipments = []  # list of equipment names
    #     abilities = []  # list of abilities names
    #
    #     is_psyker = False
    #
    #     army = self.name
    #     stats = None
    #
    #     # THIS DATA NEEDS TO BE RECORDED INDIVIDUALY TO CSV DATABASE
    #     # TODO: Create model object with each model data
    #     model = [army, fieldrole, name, stats, categories, equipments, abilities]  # unit de tuple ('M', 6)...
    #     for category in categories:
    #         if category == 'Psyker':
    #             is_psyker = True
    #
    #     if is_psyker:
    #         cast = 2
    #         deny = 1
    #         power_known = 'Smite'
    #         other_powers = []
    #         psyker_model = [cast, deny, power_known, other_powers]
    #
    #         model.extend(psyker_model)
    #     # TODO: Add rules to the database
    #     rules = []  # pass this rules to the general rule pool
    #     # TODO: Create weapon objects
    #     weapon_stats = []
    #
    #     # TODO: Create a Unit object with all this models objects
    #     unit = [fieldrole, name, models, categories, equipments, abilities]
    #
    # def get_id(self):
    #     self.serial_No += 1
    #     return self.serial_No
    #
    # def parse_unit_name_pts_pl_erase_line(self, line):
    #     if '__START OF A UNIT__' in line:
    #
    #         index = self.raw_units_text.index(line)
    #         # erase_from = index
    #
    #         # moving to Name & pts line
    #         index, line = self.move_next_line(index, self.raw_units_text)
    #         unit_name = line.split(' [')[0]
    #         pl_step, pts_step = line.split(' PL, ')
    #         unit_PL = pl_step.split('[')[1]
    #         unit_pts = pts_step.split('pts]')[0]
    #         if 'CP, ' in unit_pts:
    #             unit_pts = unit_pts.split('CP, ')[1]
    #
    #         # moving to selection line
    #         index, line = self.move_next_line(index, self.raw_units_text)
    #         selection = line[12:]
    #         # print(line)
    #
    #         # fractioned_line = line.split(', ')
    #         # print(fractioned_line)
    #
    #         return unit_name, int(unit_pts), int(unit_PL)

    def split_unit_chunks(self):

        data = self.raw_units_text

        start_index = 0
        mid_index = 0
        # max_index = len(data) - 1
        chunk = []
        has_started = False

        for line in data:
            if '__START OF A UNIT__' in line:
                start_index = data.index(line)
                has_started = True
            else:
                if has_started:
                    chunk.append(line)
                    mid_index = start_index + 1

            if '__START OF A UNIT__' in line and mid_index > start_index:
                self.all_unit_chunks.append(chunk)
                self.raw_units_text.remove(line)

                for item in chunk:
                    if item in data:
                        self.raw_units_text.remove(item)
                break

    # todo: make this block more efective?
    @staticmethod
    def get_unit_name(unit):

        line_index = 0
        name = ''

        for line in unit:
            # print(line)
            if line_index == 0:
                if ' [Legends] [' in unit[line_index]:
                    name = line.split(' [Legends] [')[0]
                else:
                    name = unit[line_index].split(' [')[0]

        return name

    @staticmethod
    def get_unit_pl(unit):
        line_index = 0
        pl = None

        for line in unit:
            if ' [Legends] [' in unit[line_index]:
                _, line = line.split(' [Legends] [')

            else:
                _, line = unit[line_index].split(' [')

            pl = int(line.split(' PL')[0])

            break
        return pl

    @staticmethod
    def get_unit_cp(unit):

        cp = None

        for line in unit:
            if 'CP, ' in line:
                cp, _ = line.split('CP, ')
                cp = int(cp.split('PL, ')[1])
            break
        return cp

    @staticmethod
    def get_unit_pts(unit):

        pts = None

        for line in unit:
            line = line.split('PL, ')[1]
            if 'CP, ' in line:
                line = line.split('CP, ')[1]
            pts = int(line.split('pts]')[0])
            break
        return pts

    @staticmethod
    def get_unit_weapons(unit):

        weapons = []

        for line in unit:
            if 'Selections:' in line:
                print(line)
            if ', Weapon: ' in line:
                print(line)
            #     line, weapon = line.split(', Weapon: ')
            #     weapons = weapon.split(', ')

        return weapons

    @staticmethod
    def get_unit_models_in_unit(unit):

        models_in_unit = None

        for line in unit:
            if 'Unit: ' in line:
                line, models_in_unit = line.split(', Unit: ')

                if models_in_unit and '[1]' not in line:

                    if ',' in models_in_unit:
                        if ', Warlord Trait: ' in models_in_unit:
                            models_in_unit, warlord_trait = models_in_unit.split(', Warlord Trait: ')
                        else:
                            models_in_unit = models_in_unit.split(', ')

        return models_in_unit

    @staticmethod
    def get_unit_warlord_trait(unit):

        warlord_trait = None

        for line in unit:
            if 'Unit: ' in line:
                line, models_in_unit = line.split(', Unit: ')

                if models_in_unit and '[1]' not in line:

                    if ',' in models_in_unit:
                        if ', Warlord Trait: ' in models_in_unit:
                            _, warlord_trait = models_in_unit.split(', Warlord Trait: ')

        return warlord_trait

    @staticmethod
    def get_unit_categories(unit):
        categories = None
        nueva_lista = []

        for line in unit:
            if 'Categories:' in line:
                a = line.split('Categories: ')[1]
                categories = a.split('Faction: ')

        if categories:
            for item in categories:
                if item:
                    # print(item.split(', '))
                    sub_item = item.split(', ')
                    for fraction in sub_item:
                        if fraction:
                            # print(fraction)
                            nueva_lista.append(fraction)

        categories = nueva_lista
        return categories

    @staticmethod
    def get_unit_wound_track(unit):

        for line in unit:
            if 'wounds' in line or 'Wound Track: ' in line or 'wounds' in line or '[1]' in line:
                wound_track = line
                # models_in_unit = line  # ???

    @staticmethod
    def get_unit_is_psyker(unit):

        is_psyker = False

        for line in unit:
            if ' Psyker: ' in line:
                # lista = line.split(', Psyker: ')[0]
                is_psyker = True

        return is_psyker

    @staticmethod
    def get_unit_psy_pow(unit):
        psy_pow = []

        for _ in unit:

            if ', Psychic Power: ' in unit:
                lista, psy_pow = unit.split(', Psychic Power: ')

        return psy_pow

    @staticmethod
    def get_unit_abilities(unit):

        abilities = []

        for line in unit:
            abilities = line.split('Abilities: ')[1]
            if ', ' in abilities:
                abilities = abilities.split(', ')

        return abilities

    def take_rules_from_units(self, unit):
        """here the 'unit' argument comes forlooped from 'test' func"""

        line_index = 0

        unit_list = []

        # name = self.get_unit_name(unit)
        # unit_list.append(name)
        # print(name)
        # pl = self.get_unit_pl(unit)
        # unit_list.append(pl)
        # cp = self.get_unit_cp(unit)
        # unit_list.append(cp)
        # pts = self.get_unit_pts(unit)
        # unit_list.append(pts)
        # categories = self.get_unit_categories(unit)
        # unit_list.append(categories)

        # weapons = self.get_unit_weapons(unit)
        # print(weapons)

        # warlord_trait = self.get_unit_warlord_trait(unit)
        # print(warlord_trait)
        # models_in_unit = self.get_unit_models_in_unit(unit)
        # print(models_in_unit)
        # abilities = self.get_unit_abilities(unit)
        # print(abilities)
        # is_psyker = self.get_unit_is_psyker(unit)
        # print(is_psyker)
        # psy_pow = self.get_unit_psy_pow(unit)
        # print(psy_pow)

        model_and_stats = self.model_stats(unit)
        # print(next(model_and_stats))

        # weapon_stats = self.weapon_stats(unit)
        index = 0
        max_index = len(unit) - 1

        description = []
        unit_data = []

        while index <= max_index:
            line = unit[index]
            # print(line)
            if line == 'Description' or line == 'Abilities' or line == 'Unit':
                pass

            else:
                unit_data.append(line)

            if line == 'Description' or len(line) < 10 and 'Unit' in line:
                while index < max_index:
                    index += 1
                    line = unit[index]
                    description.append(line)

                    # inside description there are stats for Unit, psyker, weapon. parse separatly

            index += 1
        #
        # for line in unit:
        #     print(line)

    @staticmethod
    def fix_weapon_rules(fractions):  # ['60"', 'Heavy', '4D3', '4', '0', '1', 'This', 'weapon', 'can', 'target', ...
        max_index = len(fractions) - 1
        rule_start_index = 6
        fixed_rules = ''

        if len(fractions) > 9:
            if not fractions[rule_start_index].isdigit():
                while rule_start_index <= max_index:
                    fixed_rules += fractions[rule_start_index]
                    rule_start_index += 1
                    if rule_start_index <= max_index:
                        fixed_rules += ' '
        if fixed_rules:
            new_stats = fractions[:6]
            new_stats.append(fixed_rules)
            return new_stats
        return fractions

    @staticmethod
    def fix_weapon_type(fractions):
        for fraction in fractions:
            if fraction == 'Rapid':
                at_index = fractions.index('Rapid')
                fractions.remove(fraction)
                fraction = 'Rapid Fire'
                fractions.insert(at_index, fraction)

            if fraction == 'Fire':
                fractions.remove(fraction)
        return fractions

    @staticmethod
    def model_stats(unit):
        index = 0
        max_index = len(unit) - 1
        models = []

        while index <= max_index:
            model_chunk = []
            line = unit[index]
                                                    # - M S A ends at # [4 PL, 85pts] or unit
            if line == 'M WS BS S T W A Ld Save':   # Razorback [3] (1-2 wounds remaining) 3" 6+ 5+ 6 7 N/A 1 8 3+
                                                    # f'{name} [counter] ({wounds} wounds remaining) * 6+ * 6 7 10 * 8 3+' exchange
                                                    # * 6+ * 6 7 10 * 8 3+
                                                    # Chaos Rhino3  1-2 3" 5+ 1

                index += 1

                while index <= max_index:
                    line = unit[index]
                    if line == 'Weapon':
                        break
                    model_chunk.append(line)
                    index += 1

            if model_chunk:
                # print(model_chunk)
                yield model_chunk
                # models.append(model_chunk)

            index += 1

        # return models

    def weapon_stats(self, unit):

        index = 0
        max_index = len(unit) - 1

        weapon = []

        while index <= max_index:
            line = unit[index]
            print(line)
            if 'Unit: ' in line and line[:4] == 'Unit' and '[1]' in line:
                # print(line[6:41])  # Whirlwind [1] (6+ wounds remaining)
                pass
            if line == 'Unit':
                index, line = self.move_next_line(index, unit)
                index, line = self.move_next_line(index, unit)
                # print(line)  # models name
                # while index <= max_index:
                #     index, line = self.move_next_line(index, unit)

                # if line[0] != '-' or not line[0].isdigit():
                #     break
            if line == 'Weapon':
                pass
            if self.is_quote_or_dash(line):
                fractions = line.split(' ')
                fractions = self.fix_weapon_rules(fractions)
                fraction = self.fix_weapon_type(fractions)

                # print(fractions, len(fractions)) #stats
                # index, line = self.move_next_line(index, unit)

                # print(line)

            index += 1

        return weapon

    def test(self):

        # units_headings = ['Name', 'Pts', 'PL']

        # self.unit_chunks()

        for _ in range(0, self.amount_of_units):
            self.split_unit_chunks()

        # print()
        # print(f'{self.name}')
        # print('↓ units of below army ↓')

        "↓ turn this on"
        for unit_chunk in self.all_unit_chunks:
            for line in unit_chunk:
                print(line)
                pass
            self.take_rules_from_units(unit_chunk)

        # units = []
        # for line in self.raw_units_text:
        #     unit = self.parse_unit_name_pts_pl_erase_line(line)
        #
        #     units.append(unit)
        # todo: fix error (missing units in self.raw_unit_text)

if __name__ == '__main__':
    directory = './files_in_html'

    cajlito = f'{directory}/Cajlito (HTML).html'
    machete = f'{directory}/1000pts test tau (HTML).html'
    machete2 = f'{directory}/1000pts las perras test (HTML).html'
    victor = f'{directory}/1000 BloodClaws rush (HTML).html'
    victor2 = f'{directory}/1000pts thunder rush (HTML).html'
    victor3 = f'{directory}/1000 jump rush (HTML).html'

    angels = f'{directory}/500pts DA green wing (HTML).html'
    orks = f'{directory}/4000 Orks test (HTML).html'
    orks2 = f'{directory}/6000 Orks test (HTML).html'
    tyranids = f'{directory}/1000pts Tyranids test (HTML).html'
    necrons = f'{directory}/1000pts necrons test (HTML).html'
    astra = f'{directory}/1000 pts astra militarum test (HTML).html'
    astra2 = f'{directory}/500 astra (HTML).html'
    smurf = f'{directory}/1500 Smurfs test (HTML).html'
    scars = f'{directory}/500pts white scars (HTML).html'

    all_army_list = [cajlito, machete, machete2, victor, victor2, victor3, angels, orks, orks2, tyranids, necrons,
                     astra, astra2, smurf, scars]

    data_colected_so_far = ['name', 'pts', 'CP', 'battle_type', 'detachment', 'faction', 'subfaction', 'codex',
                            'amount_of_units', 'roles', 'psychic_powers', 'units']

    # for item_ in all_army_list:
    #     try:
    #         current_army = ParseFromHtml(item_)
    #     #         print(current_army)
    #     except IndexError as e:
    #         print(f" IndexError {e}: {item_.split('/')[-1]}")
    #     except Exception as e:
    #         print(f" {Exception} {e}: {item_.split('/')[-1]}")

    current_army = ParseFromHtml(cajlito)

    # for item_ in all_army_list:
    #     current_army = ParseFromHtml(item_)
    # print(current_army)


from netCDF4 import Dataset
from osgeo import gdal, osr
from satfetcher.satellite import sources

from . import utils
from . import sources

class Processor:
    def __init__(self, source: sources.DataSource, lat: float, lon: float):
        self.source = source
        self.lat = lat
        self.lon = lon
        self.geo = sources.OWGeocodingSource()

    def process(self):
        pass

    def get_location(self):
        data = self.geo.get(self.lat, self.lon)
        return data.body[0]

class RainfallProcessor(Processor):
    def __init__(self, source: sources.DataSource, *args, **kwargs):
        super().__init__(source, *args, **kwargs)

    def process(self):
        location = self.get_location()
        data = self.source.get(lat=self.lat, lon=self.lon)

        def map_weather(weather: list):
            def fn(w):
                return { 'main': w['main'], 'description': w['description'], 'icon': w['icon'] }
            return map(fn, weather)

        def filter_main(main: dict):
            def fn(m):
                k, _ = m
                return k not in ['temp_min', 'temp_max', 'sea_level']
            return filter(fn, main.items())

        out = {
            'lat': data.body['coord']['lat'],
            'lon': data.body['coord']['lon'],
            'rain': data.body.get('rain', {}),
            'wind': data.body.get('wind', {}),
            'main': dict(filter_main(data.body['main'])),
            'weather': list(map_weather(data.body['weather'])),
            'clouds': data.body['clouds']['all'],
            'visibility': data.body['visibility'],
            'city': location['name'],
            'state': location['state'],
        }
        return out

class LightningProcessor(Processor):
    def __init__(self, source: sources.DataSource, dist: float = 50.0, *args, **kwargs):
        super().__init__(source, *args, **kwargs)
        self.dist = dist

    def process(self):
        location = self.get_location()
        samples = self.source.get(n=3)
        out = {
            'count': 0,
            'events': [],
            'city': location['name'],
            'state': location['state'],
        }

        for sample in samples:
            ds = Dataset('in-memory.nc', memory=sample.body)

            lats = ds.variables['flash_lat'][:]
            lons = ds.variables['flash_lon'][:]

            distances = utils.distance([lats, lons], [self.lat, self.lon])
            dist_mask = distances <= self.dist

            for dist, lat, lon in zip(distances[dist_mask], lats[dist_mask], lons[dist_mask]):
                out['events'].append({
                    'lat': float(lat),
                    'lon': float(lon),
                    'dist': round(float(dist), 2)
                })

            ds.close()

        out['count'] = len(out['events'])
        return out

class FireProcessor(Processor):
    def __init__(self, source: sources.DataSource, dist: float = 50.0, *args, **kwargs):
        super().__init__(source, *args, **kwargs)
        self.dist = dist

    def process(self):
        location = self.get_location()
        samples = self.source.get()
        out = {
            'count': 0,
            'events': [],
            'city': location['name'],
            'state': location['state'],
        }

        for sample in samples.body:
            props = sample['properties']
            orig = [self.lat, self.lon]
            fire = [props['latitude'], props['longitude']]

            d = utils.distance(orig, fire)
            if d <= self.dist:
                out['events'].append({
                    'lat': fire[0],
                    'lon': fire[1],
                    'dist': round(d, 2),
                    'city': props['municipio'],
                    'state': props['estado']
                })

        out['count'] = len(out['events'])
        return out

class BrightnessTemperatureProcessor(Processor):
    def __init__(self, source: sources.DataSource, lat: float, lon: float):
        super().__init__(source, lat, lon)

    def process(self):
        location = self.get_location()
        samples = self.source.get(n=5)
        temp_sum = 0

        for sample in samples:
            temp_sum += self._temperature(sample.body)

        return {
            'temp': round(temp_sum / len(samples), 2),
            'city': location['name'],
            'state': location['state']
        }

    def _temperature(self, data):
        # Min lon, Min lat, Max lon, Max lat (values for Brazil)
        extent = [-74.0, -33, -34, 0.5]
        var = 'CMI'

        # Load input file
        gdal.FileFromMemBuffer('/vsimem/file.nc', data)
        img = gdal.Open('NETCDF:/vsimem/file.nc:' + var)

        # Read the header metadata
        metadata = img.GetMetadata()
        scale = float(metadata.get(var + '#scale_factor'))
        offset = float(metadata.get(var + '#add_offset'))
        undef = float(metadata.get(var + '#_FillValue'))
        dtime = metadata.get('NC_GLOBAL#time_coverage_start')

        # Load the data
        ds = img.ReadAsArray(0, 0, img.RasterXSize, img.RasterYSize).astype(float)

        # Apply the scale, offset and convert to celsius
        ds = (ds * scale + offset) - 273.15

        # Read the original file projection and configure the output projection
        source_prj = osr.SpatialReference()
        source_prj.ImportFromProj4(img.GetProjectionRef())

        target_prj = osr.SpatialReference()
        target_prj.ImportFromProj4("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")

        # Reproject the data
        GeoT = img.GetGeoTransform()
        driver = gdal.GetDriverByName('MEM')
        raw = driver.Create('', ds.shape[0], ds.shape[1], 1, gdal.GDT_Float32)
        raw.SetGeoTransform(GeoT)
        raw.GetRasterBand(1).WriteArray(ds)

        # Define the parameters of the output file
        kwargs = {
            'format': 'MEM',
            'srcSRS': source_prj,
            'dstSRS': target_prj,
            'outputBounds': (extent[0], extent[3], extent[2], extent[1]),
            'outputBoundsSRS': target_prj,
            'outputType': gdal.GDT_Float32,
            'srcNodata': undef,
            'dstNodata': 'nan',
            'xRes': 0.02,
            'yRes': 0.02,
            'resampleAlg': gdal.GRA_NearestNeighbour
        }

        # Read number of cols and rows
        sat_data = gdal.Warp('/vsimem/fileret.nc', raw, **kwargs)
        ncol = sat_data.RasterXSize
        nrow = sat_data.RasterYSize

        # Load the data
        sat_array = sat_data.ReadAsArray(0, 0, ncol, nrow).astype(float)

        # Get geotransform
        transform = sat_data.GetGeoTransform()
        x = int((self.lon - transform[0]) / transform[1])
        y = int((transform[3] - self.lat) / -transform[5])

        # Get brightness temperature
        temp = sat_array[y,x]

        # Delete in-memory files
        gdal.Unlink('/vsimem/file.nc')
        gdal.Unlink('/vsimem/fileret.nc')

        return temp


from typing import List
class Solution:
    def maxHeight(self, cuboids: List[List[int]]) -> int:
        # rotate cube so that width<=length<=height
        for item in cuboids:
            item.sort()
        # sort by width, then length, then height
        cuboids = sorted(cuboids, key=lambda x: (x[0], x[1], x[2]))

        n = len(cuboids)
        dp = [0] * n
        # dp[i] to hold accumated height at each i
        for i, cube in enumerate(cuboids):
            dp[i] = cube[2]
            for j in range(i):
                if cube[1] >= cuboids[j][1] and cube[2] >= cuboids[j][2]:
                    dp[i] = max(dp[i], dp[j] + cube[2])

        return max(dp)


import numpy as np
import pandas as pd
from flask import Flask,request,jsonify,render_template
import pickle

app=Flask(__name__)
model=pickle.load(open('model.pkl','rb'))
modelheart=pickle.load(open('model_heart.pkl','rb'))
modellung=pickle.load(open('model_lung.pkl','rb'))
diabetes=pickle.load(open('diabetes.pkl','rb'))
hepatitis=pickle.load(open('hepatitis.pkl','rb'))
disease=pickle.load(open('disease.pkl','rb'))

@app.route('/',methods=['POST','GET'])
def home():
    if request.method=='POST':
        init_features=[]
        all_features=['receiving_blood_transfusion', 'red_sore_around_nose',
       'abnormal_menstruation', 'continuous_sneezing', 'breathlessness',
       'blackheads', 'shivering', 'dizziness', 'back_pain', 'unsteadiness',
       'yellow_crust_ooze', 'muscle_weakness', 'loss_of_balance', 'chills',
       'ulcers_on_tongue', 'stomach_bleeding', 'lack_of_concentration', 'coma',
       'neck_pain', 'weakness_of_one_body_side', 'diarrhoea',
       'receiving_unsterile_injections', 'headache', 'family_history',
       'fast_heart_rate', 'pain_behind_the_eyes', 'sweating', 'mucoid_sputum',
       'spotting_ urination', 'sunken_eyes', 'dischromic _patches', 'nausea',
       'dehydration', 'loss_of_appetite', 'abdominal_pain', 'stomach_pain',
       'yellowish_skin', 'altered_sensorium', 'chest_pain', 'muscle_wasting',
       'vomiting', 'mild_fever', 'high_fever', 'red_spots_over_body',
       'dark_urine', 'itching', 'yellowing_of_eyes', 'fatigue', 'joint_pain',
       'muscle_pain']
        print(request.form)
        doctor=pd.read_csv('people.csv')
        arr=np.asarray(doctor)
        for y in all_features:
            if y not in request.form.keys():
                init_features.append(0)
            else:
                init_features.append(1)
        print(init_features)
        final_features = [np.array(init_features)]
        prediction = disease.predict(final_features)
        # if (prediction[0] == 0):
        #     output = "Patient doesnt have parkinsons!"
        # else:
        #     output = "Patient have parkinsons!"
        output=prediction[0]
        return render_template('index.html',doctor=arr,len=10,prediction_text='Predicted class:  {val}'.format(val=output))
    else:
        doctor=pd.read_csv('people.csv')
        arr=np.asarray(doctor)
        return render_template('index.html',doctor=arr,len=10)

@app.route('/predict',methods=['POST','GET'])
def predict():
    if request.method=='POST':
        int_features = [float(x) for x in request.form.values()]
        final_features = [np.array(int_features)]
        prediction = model.predict(final_features)
        if(prediction[0]==0):
            output="Patient doesnt have parkinsons!"
        else:
            output="Patient have parkinsons!"
        return render_template('parkinson.html', prediction_text=output)
    else:
        return render_template('parkinson.html')
@app.route('/predict2',methods=['POST','GET'])
def predict2():
    if(request.method=='POST'):
        int_features=[float(x) for x in request.form.values()]
        final_feature=[np.array(int_features)]
        prediction=modelheart.predict(final_feature)
        if(prediction[0]==0):
            output="Patient doesnt have heart disease!"
        else:
            output="Patient has heart disease!"
        return render_template('heart.html', prediction_text=output)
    else:
        return render_template('heart.html')

@app.route('/predict3',methods=['POST','GET'])
def predict3():
    if(request.method=='POST'):
        int_features=[float(x) for x in request.form.values()]
        final_feature=[np.array(int_features)]
        prediction=modellung.predict(final_feature)
        if(prediction[0]==0):
            output="Patient doesnt have lung cancer!"
        else:
            output="Patient has lung cancer!"
        return render_template('lung.html', prediction_text=output)
    else:
        return render_template('lung.html')

@app.route('/predict4',methods=['POST','GET'])
def predict4():
    if(request.method=='POST'):
        int_features=[float(x) for x in request.form.values()]
        final_feature=[np.array(int_features)]
        prediction=diabetes.predict(final_feature)
        print(prediction[0])
        if(prediction[0]==0):
            output="Patient doesnt have diabetes!"
        else:
            output="Patient has diabetes!"
        return render_template('diabetes.html', prediction_text=output)
    else:
        return render_template('diabetes.html')

@app.route('/predict5',methods=['POST','GET'])
def predict5():
    if(request.method=='POST'):
        int_features=[float(x) for x in request.form.values()]
        final_feature=[np.array(int_features)]
        prediction=hepatitis.predict(final_feature)
        print(prediction[0])
        if(prediction[0]==0):
            output="Patient doesnt have hepatitis!"
        else:
            output="Patient has disease! {val}".format(val=prediction[0])
        return render_template('hepatitis.html', prediction_text=output)
    else:
        return render_template('hepatitis.html')

if __name__ == "__main__":
    app.run(debug=True)


from rest_framework import viewsets
from . import serializers
from .models import *
from datetime import datetime, timedelta
from django.db.models import Sum, Q, Count
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer
from rest_framework.views import APIView

from rest_framework.decorators import action

class InvernaderoViewset(viewsets.ModelViewSet):
    queryset = Invernadero.objects.all()
    serializer_class = serializers.InvernaderoSerializer

class ZonaViewset(viewsets.ModelViewSet):
    queryset = Zona.objects.all()
    serializer_class = serializers.ZonaSerializer
    def get_queryset(self):
        i = self.request.GET.get('invernadero', None)
        if i :
            zonas_invernadero = Zona.objects.filter(invernadero_id=i)
            print(i)
            return zonas_invernadero
        else:
            queryset = Zona.objects.all()
            return queryset

class TratamientoViewset(viewsets.ModelViewSet):
    queryset = Tratamiento.objects.all()
    serializer_class = serializers.TratamientoSerializer

class HorarioViewset(viewsets.ModelViewSet):
    queryset = Horario.objects.all()
    serializer_class = serializers.HorarioSerializer

class SolucionViewset(viewsets.ModelViewSet):
    queryset = Solucion.objects.all()
    serializer_class = serializers.SolucionSerializer

class NutrienteViewset(viewsets.ModelViewSet):
    queryset = Nutriente.objects.all()
    serializer_class = serializers.NutrienteSerializer

class PlantaViewset(viewsets.ModelViewSet):
    queryset = Planta.objects.all()
    serializer_class = serializers.PlantaSerializer

class TanqueViewset(viewsets.ModelViewSet):
    queryset = Tanque.objects.all()
    serializer_class = serializers.TanqueSerializer
    def get_queryset(self):
        i = self.request.GET.get('zona', None)
        if i :
            tanque_zona = Tanque.objects.filter(zona_id=i)
            print(i)
            return tanque_zona
        else:
            queryset = Tanque.objects.all()
            return queryset

class SensorViewset(viewsets.ModelViewSet):
    queryset = Sensor.objects.all()
    serializer_class = serializers.SensorSerializer
    def get_queryset(self):
        i = self.request.GET.get('tanque', None)
        if i :
            sensor_tanque = Sensor.objects.filter(tanque_id=i)
            print(i)
            return sensor_tanque
        else:
            queryset = Sensor.objects.all()
            return queryset


from http.server import BaseHTTPRequestHandler, HTTPServer
from multiprocessing import Process
from glob import glob
import json
import os

PATH_RESPONSE_FOLDER = "response"
PATH_CONFIG_FILE = os.path.join("config", "config.json")
PATH_HTML_FILE = os.path.join("ui", "index.html")
PATH_CSS_FILE = os.path.join("ui", "css", "index.css")
PATH_JS_FILE = os.path.join("ui", "js", "request.js")
PATH_IMG_FILE = os.path.join("ui", "img", "copy-icon.png")
HEADER_CONTENT_TYPE = "Content-Type"
HEADER_CONTENT_LENGTH = "Content-Length"
CONTENT_TYPE_JSON = "application/json"
CONTENT_TYPE_TEXT = "text/html"
CONTENT_TYPE_JS = "application/javascript"
CONTENT_TYPE_CSS = "text/css"
CONTENT_TYPE_PNG = "image/png"
STATUS_OK = 200
STATUS_ERROR = 404
JSON_INDENT = 2
ENCODING_TYPE = "UTF-8"
config = {}

class BasicServer(BaseHTTPRequestHandler):
    def handle_http(self, status, content_type, response):
        self.send_response(status)
        self.send_header(HEADER_CONTENT_TYPE, content_type)
        self.end_headers()
        self.wfile.write(bytes(response, ENCODING_TYPE))

    def do_GET(self):
        if ".css" in self.get_path():
            self.handle_http(STATUS_OK, CONTENT_TYPE_CSS, read_file(PATH_CSS_FILE))
        elif ".js" in self.get_path():
            self.handle_http(STATUS_OK, CONTENT_TYPE_JS, read_file(PATH_JS_FILE))
        elif ".png" in self.get_path():
            self.send_response(STATUS_OK)
            self.send_header(HEADER_CONTENT_TYPE, CONTENT_TYPE_PNG)
            self.end_headers()
            self.wfile.write(read_image(PATH_IMG_FILE))
        else:
            self.handle_path_request()

    def do_POST(self):
        if self.headers.get_content_type() == CONTENT_TYPE_JSON:
            length = int(self.headers.get(HEADER_CONTENT_LENGTH))
            body = self.rfile.read(length)
            if self.path == "/serviceNames":
                self.handle_http(STATUS_OK, CONTENT_TYPE_JSON, self.create_json_from_string(get_routes_as_json()))
            elif self.path == "/OPR_UPDATE":
                if self.is_data_json(body.decode(ENCODING_TYPE)):
                    name = json.loads(body.decode(ENCODING_TYPE))["serviceNameSelect"]
                    data = json.loads(body.decode(ENCODING_TYPE))["jsonTextArea"]
                    if self.is_data_json(data):
                        is_updated = update_file(os.path.join(PATH_RESPONSE_FOLDER, "{}.json".format(name)), data)
                        if is_updated:
                            self.handle_http(STATUS_OK, CONTENT_TYPE_TEXT, "JSON updated")
                        else:
                            self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "JSON is NOT updated")
                    else:
                        self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "Malformed JSON text")
                else:
                    self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "Malformed JSON")
            elif self.path == "/OPR_INSERT":
                if self.is_data_json(body.decode(ENCODING_TYPE)):
                    name = json.loads(body.decode(ENCODING_TYPE))["serviceNameInput"]
                    requested_route = self.get_route_name(name, get_route_list())
                    if requested_route:
                        self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "\"{}\" service already exists".format(name))
                    else:
                        data = json.loads(body.decode(ENCODING_TYPE))["jsonTextArea"]
                        if self.is_data_json(data):
                            is_added = write_file(os.path.join(PATH_RESPONSE_FOLDER, "{}.json".format(name)), data)
                            if is_added:
                                self.handle_http(STATUS_OK, CONTENT_TYPE_TEXT, "JSON added")
                            else:
                                self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "JSON is NOT added")
                        else:
                            self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "Malformed JSON text")
                else:
                    self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "Malformed JSON")
            elif self.path == "/OPR_SELECT":
                if self.is_data_json(body.decode(ENCODING_TYPE)):
                    name = json.loads(body.decode(ENCODING_TYPE))["serviceNameSelect"]
                    requested_route = self.get_route_name(name, get_route_list())
                    if requested_route:
                        self.handle_http(STATUS_OK, CONTENT_TYPE_JSON, self.create_json_from_file(requested_route))
                    else:
                        self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "\"{}\" service does not exist".format(name))
                else:
                    self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "Malformed JSON")
            elif self.path == "/OPR_DELETE":
                if self.is_data_json(body.decode(ENCODING_TYPE)):
                    name = json.loads(body.decode(ENCODING_TYPE))["serviceNameSelect"]
                    requested_route = self.get_route_name(name, get_route_list())
                    if requested_route:
                        is_deleted = delete_file(requested_route)
                        if is_deleted:
                            self.handle_http(STATUS_OK, CONTENT_TYPE_TEXT, "\"{}\" service JSON deleted.".format(name))
                        else:
                            self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT,
                                             "Cannot delete \"{}\" service JSON.".format(name))
                    else:
                        self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "\"{}\" service does not exist".format(name))
                else:
                    self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "Malformed JSON")
        else:
            self.handle_path_request()

    def handle_path_request(self):
        if self.path.count("/") == 1:
            if self.path.split("/")[1]:
                requested_route = self.get_route_name(self.get_path(), get_route_list())
                if requested_route:
                    self.handle_http(STATUS_OK, CONTENT_TYPE_JSON, self.create_json_from_file(requested_route))
                else:
                    self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT,
                                     "\"{}\" service response does not exist".format(self.get_path()))
            else:
                self.handle_http(STATUS_OK, CONTENT_TYPE_TEXT, read_file(PATH_HTML_FILE))
        else:
            self.handle_http(STATUS_ERROR, CONTENT_TYPE_TEXT, "Wrong path")

    @staticmethod
    def get_route_name(requested_route, routes):
        for rt in routes:
            if os.path.basename(rt).split(".")[0] == requested_route:
                return rt
        return None

    def get_path(self):
        return os.path.basename(self.path)

    @staticmethod
    def is_data_json(data):
        try:
            json.loads(data)
        except ValueError:
            return False
        return True

    @staticmethod
    def create_json_from_file(filename):
        return json.dumps(json.loads(read_file(filename)), indent=JSON_INDENT, ensure_ascii=False)

    @staticmethod
    def create_json_from_string(text):
        return json.dumps(text, indent=JSON_INDENT, ensure_ascii=False)

def read_file(path):
    res_file = None
    try:
        res_file = open(path, 'r', encoding=ENCODING_TYPE)
        file_data = res_file.read()
        res_file.close()
        return file_data
    except Exception as ex:
        if ex:
            print("Error occurred while reading file, exception message: {}".format(ex))
    finally:
        if res_file:
            res_file.close()

def read_image(path):
    res_file = None
    try:
        res_file = open(path, 'rb')
        file_data = res_file.read()
        res_file.close()
        return file_data
    except Exception as ex:
        if ex:
            print("Error occurred while reading file, exception message: {}".format(ex))
    finally:
        if res_file:
            res_file.close()

def write_file(path, data):
    res_file = None
    try:
        res_file = open(path, 'w', encoding=ENCODING_TYPE)
        res_file.write(data)
        return True
    except Exception as ex:
        print("Error occurred while writing file, exception message: {}".format(ex))
    finally:
        if res_file:
            res_file.close()

def update_file(path, updated_content):
    res_file = None
    try:
        res_file = open(path, 'r+', encoding=ENCODING_TYPE)
        res_file.read()
        res_file.seek(0)
        res_file.write(updated_content)
        res_file.truncate()
        res_file.close()
        return True
    except Exception as ex:
        print("Error occurred while writing file, exception message: {}".format(ex))
    finally:
        if res_file:
            res_file.close()

def delete_file(path):
    try:
        os.remove(path)
        return True
    except Exception as ex:
        print("Error occurred while deleting file, exception message: {}".format(ex))

def init_config():
    global config
    config = json.loads(read_file(PATH_CONFIG_FILE))

def get_route_list():
    return glob(os.path.join(PATH_RESPONSE_FOLDER, "*"))

def get_routes_as_json():
    routes = []
    route_list = get_route_list()
    route_list.sort()
    for rt in route_list:
        routes.append({"serviceNameSelect": str(os.path.basename(rt).split(".")[0])})
    return routes

def run():
    print('Starting server...')
    init_config()
    if not os.path.exists(PATH_RESPONSE_FOLDER):
        os.mkdir(PATH_RESPONSE_FOLDER)
    server_address = (config['ip'], int(config['port']))
    httpd = HTTPServer(server_address, BasicServer)
    print("Server running on port: {}".format(config['port']))
    httpd.serve_forever()

if __name__ == '__main__':
    p = Process(target=run())
    p.start()
    p.join()