#! /usr/bin/env python
# -*- coding: Utf-8 -*-

#######################################################
# Agyuparbaj - server resz                            #
# (C) Gerard Swinnen, Verviers (Belgique) - July 2004 #
# Licence : GPL                                       #
# A script vegrehajtasa elott ellenorizze, hogy az    #
# alabbi IP cim a host IP cime.                       #
# Valaszthat egy eltero portszamot, vagy megvaltoztat-#
# hatja a jatekter mereteit.                          #
# Minden esetben ellenorizze, hogy ugyanezeket a val- #
# toztatasokat elvegezte-e a kliens scriptek          #
# mindegyiken.                                        #
#######################################################

host, port = '192.168.1.9', 35000
width_, height_ = 700, 400             # a jatekter meretei

from Tkinter import *
import socket, sys, threading, time
import canon03
from canon04 import Canon, AppAgyuParbaj

class VezerloPult(canon03.VezerloPult):
    """Tokeletesitett vezerlo pult""" 
    def __init__(self, boss, canon):
        canon03.VezerloPult.__init__(self, boss, canon)

    def tuzel(self):
        "az asszocialt agyu lovesenek elinditasa"
        self.appli.tuzel_agyu(self.canon.id)
        
    def iranyzas(self, angle):
        "az asszocialt agyu dolesszogenek beallitasa"
        self.appli.iranyzas_agyu(self.canon.id, angle)

    def pont_ertek(self, sc =None):
        "új <sc> pontszam kiirasa, vagy a letezo olvasasa"
        if sc == None:
            return self.score
        else:
            self.score =sc
            self.pontok.config(text = ' %s ' % self.score)

    def inactivate(self):
        "a tuzgomb es a szogbeallito rendszer inaktivalasa"
        self.bTuz.config(state =DISABLED)
        self.celzas.config(state =DISABLED) 

    def activate(self):
        "a tuzgomb es a szogbeallito rendszer aktivalasa"
        self.bTuz.config(state =NORMAL)
        self.celzas.config(state =NORMAL)
        
    def beallitas(self, angle):
        "a kurzor poziciojanak megvaltoztatasa"
        self.celzas.config(state =NORMAL)
        self.celzas.set(angle)
        self.celzas.config(state =DISABLED)

class ThreadConnexion(threading.Thread):
    """egy klienskapcsolatot kezelo thread objektum"""
    def __init__(self, boss, conn):
        threading.Thread.__init__(self)
        self.connection = conn           # a kapcsolat socket-jenek hivatkozasa
        self.app = boss                 # az alkalmazasablak hivatkozasa

    def run(self):
        "a klienstol kapott uzenetre valaszul vegrehajtott akciok"
        name = self.getName()            # kliens id-je = a thread neve
        while 1:
            msgClient = self.connection.recv(1024)
            print "**%s** %s" % (msgClient, name)
            deb = msgClient.split(',')[0]
            if deb == "fin" or deb =="":
                self.app.agyu_eltavolitas(name)
                # a tobbi kliens ertesitese az agyu eltavolitasarol :
                self.app.locking.acquire()
                for cli in self.app.conn_client:
                    if cli != name:
                        message = "megszűnik,%s" % name
                        self.app.conn_client[cli].send(message)
                self.app.locking.release()
                # az aktualis thread zarasa :
                break
            elif deb =="client OK":
                # kozli az uj klienssel a mar bejegyzett agyukat :
                msg ="ágyúk,"
                for g in self.app.guns:
                    gun = self.app.guns[g]
                    msg =msg +"%s;%s;%s;%s;%s," % \
                              (gun.id, gun.x1, gun.y1, gun.irany, gun.szin)
                self.app.locking.acquire()
                self.connection.send(msg)
                # fogadas nyugtazasat varja ('OK') :
                self.connection.recv(100)
                self.app.locking.release()
                # a server jatekterehez hozzaad egy agyut.
                # a hivott metodus a letrehozott agyu jellemzoit adja meg visszateresi ertekkent :
                x, y, irany, szin = self.app.agyu_hozzadasa(name)
                # ennek az uj agyunak a jellemzoit megadja az osszes tobbi
                # mar felkapcsolodott kliensnek :
                self.app.locking.acquire()
                for cli in self.app.conn_client:
                    msg ="új_ágyú,%s,%s,%s,%s,%s" % \
                                       (name, x, y, irany, szin)
                    # az uj kliensnek egy mezot ad, ami jelzi, hogy 
                    # az uzenet az o agyujara vonatkozik :
                    if cli == name:
                        msg =msg +",az_öné"
                    self.app.conn_client[cli].send(msg)
                self.app.locking.release()
            elif deb =='tűz':
                self.app.tuzel_agyu(name)
                # jelzi ezt a lovest az osszes tobbi kliensnek :
                self.app.locking.acquire()
                for cli in self.app.conn_client:
                    if cli != name:
                        message = "tüzel,%s," % name
                        self.app.conn_client[cli].send(message)        
                self.app.locking.release()
            elif deb =="célzás":
                t =msgClient.split(',')
                # tobb szoget kaphatunk, hasznaljuk az utolsot : 
                self.app.iranyzas_agyu(name, t[-2])
                # Az osszes tobbi kliensnek jelezzuk a valtozast :
                self.app.locking.acquire()
                for cli in self.app.conn_client:
                    if cli != name:
                        # záró vessző, mivel az uzenetek neha csoportositva vannak :
                        message = "szög,%s,%s," % (name, t[-2])
                        self.app.conn_client[cli].send(message)
                self.app.locking.release()
                    
        # Kapcsolat zarasa :
        self.connection.close()          # megszakitja a kapcsolatot
        del self.app.conn_client[name]   # a szotarban toroljuk a hivatkozasat
        self.app.kiir("A %s kliens lekapcsolódik.\n" % name)
        # A thread itt fejezodik be

class ThreadClients(threading.Thread):
    """az uj klienskapcsolatokat kezelo thread-objektum"""
    def __init__(self, boss, connec):
        threading.Thread.__init__(self)
        self.boss = boss                # az alkalmazasablak hivatkozasa
        self.connec = connec            # a kezdo socket hivatkozasa
        
    def run(self):
        "uj klienskapcsolatok varasa es kezelese "
        txt ="Server kész, várja a kéréseket ...\n"
        self.boss.kiir(txt)
        self.connec.listen(5) 
        # A kliensek altal kert kapcsolatok kezelese :
        while 1:    
            new_conn, adresse = self.connec.accept()
            # Egy uj thread-objektum letrehozasa a kapcsolat kezelesere :
            th = ThreadConnexion(self.boss, new_conn)
            th.start()
            it = th.getName()        # a thread egyedi azonositoja
            # A kapcsolat tarolasa a szotarban :
            self.boss.kapcsolat_bejegyzese(new_conn, it)
            # Kiir :
            txt = "%s kliens felkapcsolódik, IP cím %s, port %s.\n" %\
                   (it, adresse[0], adresse[1])
            self.boss.kiir(txt)
            # A parbeszed elkezdese a klienssel :
            new_conn.send("server OK")

class AppServer(AppAgyuParbaj):
    """az alkalmazas foablaka (server vagy kliens)"""
    def __init__(self, host, port, width_c, height_c):
        self.host, self.port = host, port
        AppAgyuParbaj.__init__(self, width_c, height_c)        
        self.active =1          # aktivitas-flag
        # ugyeljunk a megfelelo kilepesre ha bezarjuk az ablakot :
        self.bind('<Destroy>',self.threadek_zarasa)

    def specificites(self):
        "a server resz specialis objektumainak elkeszitese"    
        self.master.title('<<< Az agyuparbaj jatek servere >>>')
        
        # egy gorgeto savval asszocialt Text widget :
        st =Frame(self)
        self.notice =Text(st, width =85, height =5)
        self.notice.pack(side =LEFT)
        scroll =Scrollbar(st, command =self.notice.yview)
        self.notice.configure(yscrollcommand =scroll.set)
        scroll.pack(side =RIGHT, fill =Y)
        st.pack()
        
        # halozati server resz :
        self.conn_client = {}           # klienskapcsolatok szotara
        self.locking =threading.Lock()   # retesz a thread-ek szinkronizalasahoz
        # A server inicializalasa - Socket letrehozasa:
        connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            connection.bind((self.host, self.port))
        except socket.error:
            txt ="A socket kapcsolódása a %s host, %s porthoz meghiúsult.\n" %\
                  (self.host, self.port)
            self.notice.insert(END, txt)
            self.reception =None
        else:
            # a kliensek kapcsolodasat figyelo thread inditasa :
            self.reception = ThreadClients(self, connection)
            self.reception.start()

    def agyu_veletlen_mozditasa(self, id):
        "az <id> agyu veletlenszeru elmozditasa"
        x, y = AppAgyuParbaj.agyu_veletlen_mozditasa(self, id)
        # az uj koordinatak kozlese az osszes klienssel :
        self.locking.acquire()
        for cli in self.conn_client:
            message = "elmozdul,%s,%s,%s," % (id, x, y)
            self.conn_client[cli].send(message)
        self.locking.release()
 
    def goal(self, i, j):
        "az <i> agyu jelzi, hogy eltalalta a <j> ellenfelet"
        AppAgyuParbaj.goal(self, i, j)
        # az osszes klienssel tudatjuk az uj pontszamokat :
        self.locking.acquire()
        for cli in self.conn_client:
            msg ='pontszám,'
            for id in self.pult:
                sc = self.pult[id].pont_ertek()
                msg = msg +"%s;%s," % (id, sc)
            self.conn_client[cli].send(msg)
        time.sleep(.5)               # az üzenetek jobb szeparalasa erdekeben 
        self.locking.release()

    def agyu_hozzadasa(self, id):
        "egy <id> nevu agyu es vezerlopult letrehozasa 2 szotarban"
        # valtogatni fogjuk a 2 taboret :
        n = len(self.guns)
        if n %2 ==0:
            irany = -1
        else:
            irany = 1
        x, y = self.veletlen_koord(irany)
        szin =('dark blue', 'dark red', 'dark green', 'purple',
               'dark cyan', 'red', 'cyan', 'orange', 'blue', 'violet')[n]
        self.guns[id] = Canon(self.jatek, id, x, y, irany, szin)
        self.pult[id] = VezerloPult(self, self.guns[id])
        self.pult[id].inactivate()
        return (x, y, irany, szin)
        
    def agyu_eltavolitas(self, id):
        "az <id> agyu es vezerlopult eltavolitasa"
        if self.active == 0:        # az ablakot bezartuk
            return                  
        self.guns[id].torol()
        del self.guns[id]
        self.pult[id].destroy()
        del self.pult[id]
        
    def iranyzas_agyu(self, id, angle):
        "az <id> agyu dolesszogenek <angle> ertekre valo beallitasa"
        self.guns[id].iranyzas(angle)
        self.pult[id].beallitas(angle)    
  
    def tuzel_agyu(self, id):
        "az <id> agyu lovesenek inditasa"
        self.guns[id].tuz()

    def kapcsolat_bejegyzese(self, conn, it):
        "A kapcsolat tarolasa egy szotarba"
        self.conn_client[it] = conn

    def kiir(self, txt):
        "egy üzenet kiirasa a szovegzonaba"
        self.notice.insert(END, txt)
 
    def threadek_zarasa(self, evt):
        "a letezo kapcsolatok megszakitasa es a thread-ek zarasa"
        # az osszes klienssel letrehozott kapcsolat megszakitasa :
        for id in self.conn_client:
            self.conn_client[id].send('fin')
        # a keresekre varo server thread befejezesenek kenyszeritese :
        if self.reception != None:
            self.reception._Thread__stop()
        self.active =0                  # megakadalyozza a tovabbi hozzafereseket a Tk -hoz

if __name__ =='__main__':
    AppServer(host, port, width_, height_).mainloop()
    
#connex -> connec