# AGPL 3 or any later version
# (C) J.Y.Amihud ( Blender Dumbass )

from http.server import BaseHTTPRequestHandler, HTTPServer
from subprocess import *
import json
import os
import time
import random
import datetime
import hashlib
import urllib.request
import urllib.parse
import subprocess
import os

from modules import Set
from modules import Render
from modules.Common import *

class handler(BaseHTTPRequestHandler):

    def log_message(self, format, *args):

        if "?" in self.path:
            self.path = self.path[:self.path.find("?")]

        q = clr["tbbl"]
        b = clr["tbbl"]

        
        try:
            if self.newview:
                b = clr["bold"]+clr["tbrd"]
        
            for i in self.parsed:
                if i != "password":
                    q = q + "[ "+i+" : "+self.parsed[i][0]+" ] "
                else:
                    q = q + "[ "+i+" : ******* ] "

            cookie = self.cookie

            toprint = consoleForm(cookie)+" "+b+"[ "+str(datetime.datetime.now())+" ] "+self.path+" "+q
            
        except:
            
            cookie = None
            
            toprint = consoleForm(cookie)+" "+b+"[ "+str(datetime.datetime.now())+" ] "+self.requestline
        
        print(toprint)

        folder = Set.Folder()
        filename = folder+"/logs/"+datetime.datetime.now().strftime('%Y-%m-%d')+".log"
        logfile = open(filename, "ab")
        logfile.write((toprint+"\n").encode('utf-8'))
        logfile.close()

    def do_POST(self):

        self.path = self.path.replace("/..", "/")
        self.path = self.path.replace("%27", "'")

        self.cookie = self.headers.get("Cookie")
        self.newview = False
        if self.cookie: self.cookie = self.cookie[-200:]

        # Failing early to make sure that nobody will
        # try attacking this part of the server.
        
        commands = ["do_edit",
                    "do_login",
                    "do_register",
                    "change_password"]
        
        found = False
        for i in commands:
            if i in self.path:
                found = True
                break
        if not found:
            Render.AccessDenied(self)
            return
        
        
        # Not allowing more than 1 MB for the sake of
        # network. A full book of Sheiny The Hacker
        # which was posted on blenderdumbass.org is
        # only about 160 KB. 1MB should be plenty.
        
        length = int(self.headers["Content-Length"])
        if length < 1000000:
            try:
                text = self.rfile.read(length).decode("utf-8")
            except:
                Render.AccessDenied(self)
                return

        else:
            Render.AccessDenied(self)
            return
        
        #parsed_url = urllib.parse.urlparse(text)
        self.parsed = urllib.parse.parse_qs(text)

        if self.path[1:].startswith("do_edit"):
            Render.Publish(self)

        elif self.path[1:].startswith("do_login"):
            Render.Login(self)

        elif self.path[1:].startswith("change_password"):
            Render.UpdatePassword(self)

        elif self.path[1:].startswith("do_register"):
            Render.Register(self)
            
        else:
            Render.NotFound(self)
        
    def do_GET(self):

        self.path = self.path.replace("/..", "/")
        self.path = self.path.replace("%27", "'")
        self.path = self.path.replace("%22", '"')

        parsed_url = urllib.parse.urlparse(self.path)
        self.parsed = urllib.parse.parse_qs(parsed_url.query)
        
        self.cookie = self.headers.get("Cookie")
        if self.cookie: self.cookie = self.cookie[-200:]

        # ignore = ["/rss"]
        
        # if not self.cookie and not self.path.startswith(tuple(ignore)):
        #     Render.Redirect(self, self.path)
        #     return

        self.newview = False
        
        categories = list(Render.tabs().keys())
        
        if self.path[:self.path.find("?")] == "/" or self.path == "/":
            Render.MainPage(self)

        elif self.path[1:] in categories or self.path[1:self.path.find("?")] in categories:
            url = self.path[1:]
            if "?" in url: url = url[:url.find("?")]
            Render.ListPage(self, url)

        elif self.path[1:].startswith(tuple(categories)):
            url = self.path[1:]
            if "?" in url: url = url[:url.find("?")]
            try:
                Render.ArticlePage(self, url)
            except:
                Render.NotFound(self)

        elif self.path[1:].startswith("account"):
            url = self.path[9:]
            if "?" in url: url = url[:url.find("?")]
            try:
                Render.AccountPage(self, url)
            except:
                Render.NotFound(self)

        elif self.path[1:].startswith("login"):
            Render.LoginPage(self)

        elif self.path[1:].startswith("editor"):
            Render.EditorPage(self)

        elif self.path[1:].startswith("email_verify"):

            from modules import Email
            Email.VerifyPage(self)

        elif self.path[1:].startswith("register"):
            Render.RegisterPage(self)
            
        elif self.path[1:].startswith("settings"):
            Render.SettingsPage(self)

        elif self.path[1:].startswith("comment"):
            Render.DoComment(self)

        elif self.path[1:].startswith("delete_comment"):
            Render.DeleteComment(self)

        elif self.path[1:].startswith("update_account"):
            Render.UpdateAccount(self)

        elif self.path[1:].startswith("grant_publication_rights"):
            Render.UpdatePublicationRights(self)

        elif self.path[1:].startswith("create_invite"):
            Render.CreateInvite(self)
            
        elif self.path[1:].startswith("cancel_invite"):
            Render.CancelInvite(self)

        elif self.path[1:].startswith("log_out"):
            Render.LogOut(self)

        

        

        elif self.path[1:].startswith("read_notification"):
            Render.ReadNotification(self)

        elif self.path[1:].startswith("search"):
            Render.Search(self)
            

        elif self.path.startswith("/graph/"):
            url = self.path[6:]
            if "?" in url: url = url[:url.find("?")]
            Render.Graph(self, url)

        elif self.path.startswith("/rss"):
            Render.RSS(self)
   
        elif self.path.startswith("/pictures/"):

            try:
                folder = Set.Folder()
                f = open(folder+self.path, "rb")
                f = f.read()
                Render.headers(self, 200)
                self.wfile.write(f)
            except:
                Render.NotFound(self)

        elif self.path == "/css":

            config = Set.Load()
            filename = config.get("css", "default.css")
            cssfile = open(filename, "rb")
            cssfile = cssfile.read()
            Render.headers(self, 200)
            self.wfile.write(cssfile)

        elif self.path.startswith("/icon/"):
            
            folder = "icons"
            icon = folder+"/"+self.path[6:]+".png"
            f = open(icon, "rb")
            f = f.read()
            Render.headers(self, 200)
            self.wfile.write(f)

        else:
            Render.NotFound(self)
    
config = Set.Load()
PORT = config.get("port", 8080)
serve = HTTPServer(("", PORT), handler)
try:
    serve.serve_forever()
except KeyboardInterrupt:
    print("\nServer Stopped!")