# vDial-up client
# Copyright (C) 2015 - 2017 Nathaniel Olsen
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from time import sleep
import socket
import libs.vDialupcore as core
from multiprocessing import Process
import sys
import struct

def MD5SUM_mismatch(vNumber_to_connect, sock):
    print("*Warning: The server's MD5SUM does not match with the one listed on file, Do you wish to continue? (Y/N)")
    if vNumber_to_connect == core.RegServ_vNumber:
        MD5SUM_on_file = core.RegServ_MD5SUM
    else:
        pass # Right now, there is no way to retrieve a server's md5sum until I implement md5sum retriving in RegServ.
    print("MD5SUM on file: %s" % (MD5SUM_on_file))
    print("MD5SUM according to server: %s" % (received.split()[1]))
    print("")
    choice = input("Enter choice (Y/N): ")
    if choice == 'Y' or choice == 'y':
        init(sock, vNumber_to_connect)
    if choice == 'N' or choice == 'n':
        sys.exit() # Exit for now.

class main():
    def send_msg(sock, msg):
        # Prefix each message with a 4-byte length (network byte order)
        msg = struct.pack('>I', len(msg)) + str.encode(msg)
        sock.sendall(msg)

    def recv_msg(sock):
        # Read message length and unpack it into an integer
        raw_msglen = main.recvall(sock, 4)
        if not raw_msglen:
            return None
        msglen = struct.unpack('>I', str.encode(raw_msglen))[0]
        return main.recvall(sock, msglen)

    def recvall(sock, n):
        # Helper function to recv n bytes or return None if EOF is hit
        


    def servping(sock):
        while 1:
            sleep(20)
            sock.sendall(bytes("SERVPING" + "\n", "utf-8"))
            if main.listen_for_data(sock) == "PONG":
                break
            else:
                print("Disconnected: Connection timeout.")

    def vdialing(vNumber_to_connect, vNumber_IP):
        if core.config['use_ipv6_when_possible']:
            sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        else:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print("vDialing %s..." % (vNumber_to_connect))
        if core.config['vDial-up Settings']['vNumber'] == "000000000":
            core.dialupnoise()
            try:
                sock.connect((vNumber_IP, 5000))
            except ConnectionRefusedError:
                print("Error: Connection Refused.")
                sys.exit()
            main.send_msg(sock, "INITPING")

            if main.recv_msg(sock) == "PONG":
                print("Connected.")
                #Process(target=main.servping, args=[sock]).start() # The ability to check if a server connection is still alive is coming soon.
                main.send_msg(sock, "MD5SUMCHECK")
                if main.recv_msg(sock).split()[0] == "MD5SUM:":
                    if main.recv_msg(sock).split()[1] == core.RegServ_MD5SUM:
                        print("MD5SUM verification was succeeded.")
                    else:
                        MD5SUM_mismatch(vNumber_to_connect, sock)
                else:
                    print("Error: Unable to retrieve MD5SUM.")
                main.init(sock, vNumber_to_connect)
            else:
                print("Error: Server did not properly respond to INITPING, disconnecting.")

        else:
            Process(target=core.dialupnoise()).start()
            sock.connect((vNumber_IP, 5000))
            main.send_msg(sock, "INITPING")
            if main.recv_msg(sock) == "PONG":
                print("Connected to Registation Server!")
                main.send_msg(sock, "MD5SUMCHECK")
                if main.recv_msg(sock).split()[0] == "MD5SUM:":
                    if main.recv_msg(sock).split()[1] == core.RegServ_MD5SUM:
                        print("MD5SUM verification was succeeded.")
                    else:
                        MD5SUM_mismatch(vNumber_to_connect, sock)
                else:
                    print("Error: Unable to retrieve MD5SUM.")
            else:
                print("Error: Server did not properly respond to INITPING, disconnecting.")


    def init(sock, vNumber_to_connect):
        main.send_msg(sock, "VNUMBER: {}".format(core.config['vDial-up Settings']['vNumber']))
        if core.config['vDial-up Settings']['vNumber'] == "000000000":
           main.send_msg(sock, "CLIENTREGISTER")
           if main.recv_msg(sock).split()[0] == "CONFIG:":
               if main.recv_msg(sock).split()[1] == "vNumber":
                   core.config['vDial-up Settings']['vNumber'] = main.recv_msg(sock).split()[2]
                   core.saveconfig()
               if main.recv_msg(sock).split()[1] == "Key":
                   core.config['vDial-up Settings']['Key'] = main.recv_msg(sock).split()[2]
                   core.saveconfig()
               if main.recv_msg(sock).split()[0] == "TOCLIENT:":
                   print(" ".join(main.recv_msg(sock).split()[2:]))
        else:
            main.send_msg(sock, "KEY: {}".format(core.config['vDial-up Settings']['Key']))
            main.send_msg(sock, "INIT")

data = ''
        while len(data) < n:
            packet = (sock.recv(n - len(data)).decode('utf-8'))
            if not packet:
                return None

            data += packet
        return data