##############################################################################
# -*- coding: utf-8 -*-
# Project:     ControlIES
# Module:    Hosts.py
# Purpose:     Hosts class
# Language:    Python 2.5
# Date:        7-Feb-2011.
# Ver:        7-Feb-2011.
# Author:	Manuel Mora Gordillo
#			Francisco Mendez Palma
# Copyright:    2011 - Manuel Mora Gordillo <manuito @no-spam@ gmail.com>
#				2011 - Francisco Mendez Palma <fmendezpalma @no-spam@ gmail.com>
#
# ControlIES 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.
# ControlIES 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 ControlIES. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

import ldap
import logging
import time
from math import ceil
from operator import itemgetter

class Hosts(object):

    def __init__(self):
		pass
	
    def __init__(self,ldap,name,ip,mac,group,type):
		self.ldap = ldap
		self.name = name
		self.ip = ip
		self.mac = mac
		self.group = group 
		self.type = type
	
    def getName (self):
		return self.mac	
				
    def validation(self,action):

		if action == "add":
			if self.type == "none":
				return "type"
		
		if self.name == "":
			return "name"
			
		if self.type <> 'thinclient':
			if self.ip == "":
				return "ip"

		if self.mac == "":
			return "mac"
			
		if self.type =="thinclient":
			if self.group == "":
				return "group"

		if self.type == "":
			return "type"
		
		if action == "add":
			if self.existsHostname():
				return "hostAlreadyExists"
		
			# thinclients no requieren ip, la cogen dinamicamente en el aula
			if self.type <> "thinclient":
				if self.existsIP():
					return "ipAlreadyExists"
			#controlar overflow en nodos		
			if self.groupOverflow(300):
				return "groupOverflow"

			if self.existsMAC():
				return "macAlreadyExists"

		elif action == "modify":			
			return "OK"

		return "OK"		
		
    def process(self,action):
		import pdb
		if action == "add":
			val = self.validation(action)
			
			if val != "OK":
				return val
			else:
				response = self.add()
				return response

		if action == "modify":
			val = self.validation()
			
			if val != "OK":
				return val
			else:
				response = self.modify()
				return response
				
		if action == "delete":
			response = self.delete()
			return response
		
		if action == "list":
			response = self.list();
			return response	
			
    def list(self,args):
		
		#from Plugins.LdapConnection import LdapConnection

		#l = LdapConnection("172.23.36.5",'cn=admin,ou=People,dc=instituto,dc=extremadura,dc=es',"Sta1987teleco")
		#l.connect()
		
		# grid parameters
		limit = int(args['rows'][0])
		page = int(args['page'][0])
		start = limit * page - limit
		finish = start + limit;				

		# sort by field
		sortBy = args['sidx'][0]
		#if sortBy == "uid":
			#sortBy = "id"

		# reverse Sort
		reverseSort = False
		if args['sord'][0] == "asc":
			reverseSort = True
		
		#Distinguimos entre hosts ltsp, workstations y portatiles
		type = args['type'][0]
		
						
		if type == "ltsp":
			# Obtengo todos los elementos del nodo hosts
			#search = l.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])
			#filter = self.buildFilter(args)		
			search = self.ldap.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])		
			
			# triplets que contiene los nombres de los ltsp-servers
			hostnames = self.getLTSPServers()
							
			# Ahora tengo que quedarme con los elementos de search que estan en hostnames: los que son ltsp
			resultado=list()
			for element in search:
				if element[0][1]["cn"][0] in hostnames:
					resultado.append(element)
			
			search = resultado 

			rows = []
			for i in search:
				row = {
					"id":i[0][1]["cn"][0], 
					"cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]],
					"cn":i[0][1]["cn"][0],
					"ipHostNumber":i[0][1]["ipHostNumber"][0],
					"macAddress":i[0][1]["macAddress"][0]
				}
				#row = { "cn":i[0][0], "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]]}
				rows.append(row)
				
			if len(rows) > 0:
				totalPages = ceil( len(rows) / int(limit) )
			else:
				totalPages = 0
			if page > totalPages:
				page = totalPages

			result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
			return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish]  }		
				
		elif type == "thinclient":
			search = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn=*",["cn","dhcpHWAddress"])
			filter="(|(dhcpOption=*subnet*)(dhcpOption=*log*))"
			import pdb
			
			rows = []
			
			# esto hay que cambiarlo: tenemos 4 groups en thinclientes
			for i in search[6:len(search)]:
					nodeinfo=i[0][0].replace ("cn=","").split(",")
					row = {
						"id":i[0][1]["cn"][0], 
						"cell":[i[0][1]["cn"][0], i[0][1]["dhcpHWAddress"][0].replace("ethernet ",""), nodeinfo[1]],
						"cn":i[0][1]["cn"][0],
						"dhcpHWAddress":i[0][1]["dhcpHWAddress"][0],
						"groupName":i[0][1]["dhcpHWAddress"][0]
					}						
					rows.append(row)
			if len(rows) > 0:
				totalPages = ceil( len(rows) / int(limit) )
			else:
				totalPages = 0
			if page > totalPages:
				page = totalPages
				
			result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
			return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish] }					
		
		elif type == "workstation":
			# Obtengo todos los elementos del nodo hosts
			#search = l.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])
			search = self.ldap.search("ou=hosts","cn=*",["cn","ipHostNumber","macAddress"])					
			# triplets que contiene los nombres de las workstations
			#triplets = l.search("ou=Netgroup","cn=workstation-hosts",["nisNetgroupTriple"])
			triplets = self.ldap.search("ou=Netgroup","cn=workstation-hosts",["nisNetgroupTriple"])
			triplets = triplets [0][0][1]["nisNetgroupTriple"]
			hostnames=list()
			
			# obtengo lista de nombres de los hosts workstation
			for node in triplets:
				name = node.replace(",-,-)","").replace("(","")
				hostnames.append(name)
				
			# Ahora tengo que quedarme con los elementos de search que estan en hostnames
			resultado=list()
			for element in search:
				if element[0][1]["cn"][0] in hostnames:
					resultado.append(element)
			
			search = resultado 

			rows = []
			for i in search:
				row = {
					"id":i[0][1]["cn"][0], 
					"cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]],
					"cn":i[0][1]["cn"][0],
					"ipHostNumber":i[0][1]["ipHostNumber"][0],
					"macAddress":i[0][1]["macAddress"][0]
				}						
				#row = { "cn":i[0][0], "cell":[i[0][1]["cn"][0], i[0][1]["ipHostNumber"][0],i[0][1]["macAddress"]]}
				rows.append(row)

			if len(rows) > 0:
				totalPages = ceil( len(rows) / int(limit) )
			else:
				totalPages = 0
			if page > totalPages:
				page = totalPages					

			result = sorted(rows, key=itemgetter(sortBy), reverse=reverseSort)
			return { "page":page, "total":totalPages, "records":len(rows), "rows":result[start:finish] }		

    def add(self):
		if self.type=="thinclient":
			attr = [
			('objectclass', ['top','dhcpHost']),
			('cn', [self.name] ),
			('dhcpStatements', ['filename "/var/lib/tftpboot/ltsp/i386/pxelinux.0"'] ),	
			('dhcpHWAddress', ['ethernet ' + self.mac] )
			]
			
			self.ldap.add("cn="+self.name +",cn="+self.group+",cn=THINCLIENTS,cn=DHCP Config", attr)
						
		return "OK"
		
    def modify(self):
		mod_attrs = [
		(ldap.MOD_ADD, 'description', 'Author of New Organon'),
		(ldap.MOD_ADD, 'description', 'British empiricist') 
		]
		self.ldap.modify_s('uid='+ uid +',cn=hosts', mod_attrs)

    def delete(self):
		if self.type=="thinclient":
			self.ldap.delete('cn='+ self.name +',cn=' +self.group +',cn=THINCLIENTS,cn=DHCP Config')

		return "OK"		

    def wakeup(self):
		from Plugins import NetworkUtils
		NetworkUtils.startup(self.mac)
		
    def groupOverflow(self,overflow):
		import pdb
		if self.type == 'thinclient':
			search = self.ldap.search("cn=" + self.group +",cn=THINCLIENTS,cn=DHCP Config","cn=*",["cn"])
			if len(search)-2 >= overflow:
				return True
				
		return False
			
    def existsHostname(self):
		
		if self.type == 'thinclient':
			result = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn="+self.name,["cn"])
		else:
			result = self.ldap.search("ou=hosts","cn="+self.name,["cn"])
		
		if len(result) > 0:
			return True
		
		return False
		
    def existsMAC(self):
		# Compruebo con las macs de la rama hosts
		if self.type == 'thinclient':
			result = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","dhcpHWAddress=*",["dhcpHWAddress"])

			for i in range (0, len(result) - 1):
				if result [i][0][1]['dhcpHWAddress'][0].replace ("ethernet ", "") == self.mac:
					return True

		else:
			result = self.ldap.search("ou=hosts","macAddress="+self.mac,["macAddress"])

			if len(result) > 0:
				return True
		
		return False
		
    def existsIP (self):
		# Cojo las ips de la rama hosts -> arpa -> in-addr
		result = self.ldap.search ("dc=23,dc=172,dc=in-addr,dc=arpa,ou=hosts", "dc=*",["associatedDomain"])
		
		myIP = self.ip.split (".")

		for i in range (0, len (result) -1):
			reverseIP = result [i][0][1]['associatedDomain'][0].replace (".in-addr.arpa","").split(".")
			reverseIP.reverse() 
			if myIP == reverseIP:
				return True
		
		return False
		
    def getThinclientGroups (self):
		import pdb

		groups = []
		search = self.ldap.search("cn=THINCLIENTS,cn=DHCP Config","cn=group*",["cn"])
		
		for g in search:
			groups.append (g[0][1]["cn"][0])
			
		return { "groups":groups }
		
		
    def getLTSPServers (self):
		triplets = self.ldap.search("ou=Netgroup","cn=ltsp-server-hosts",["nisNetgroupTriple"])
		triplets = triplets [0][0][1]["nisNetgroupTriple"]
		hostnames=list()
			
		for node in triplets:
			name = node.replace(",-,-)","").replace("(","")
			hostnames.append(name)
		hostnames.sort()
		return hostnames


    def getLTSPStatus (self):
		from Utils.avahiClient import avahiClient
		import threading
		
		a = avahiClient()  
		a.start() 
		time.sleep(1000) 	
		a.cancel()		
		names = a.getList()
		print names
		
		"""a = avahiClient()
		time.sleep(1000) 		
		names = a.getList()
		print names
		a.kill()"""
		return names

#	def wakeup(self):
#		from twisted.internet.task import LoopingCall
#		from twisted.internet import defer
#		from Plugins import NetworkUtils
#		NetworkUtils.startup(self.mac)
		

# Encender el equipo
#def wakeup(self):
#        macs=[]
#        for i in self.targets:
#            mac=Configs.MonitorConfigs.GetMAC(i)
#            if mac !='':                
#                macs.append(mac)                
#        Actions.sendWOLBurst(macs, 2)

#Apagar el equipo
#    def sleep(self):
#        self.usersCommand(Desktop.sleep)

#def sendWOLBurst(macs,throttle):    
#    from twisted.internet.task import LoopingCall    
#    from twisted.internet import defer    
#    if not macs:
#        return defer.succeed(None)
#    d = defer.Deferred()
#    work = list(macs)
#    def sendNext():
#        if not work:
#            loop.stop()
#            d.callback(None)
#            return defer.succeed(None)
#        next = work.pop(0)
#
#        #subprocess.Popen(['wakeonlan',next ])
#        #subprocess.Popen(['wakeonlan','-i','192.168.0.255',next ])
#        NetworkUtils.startup(next)
#                   
#        return None
#    loop = LoopingCall(sendNext)
#    loop.start(throttle)
#    return d
