#!/usr/bin/env python3
#============================================================================================
# Call mongo utility web service
# optional param using end of url:    lname=<instructor_lname>
# optional param using command line:  <instructor_lname>
# call web service to obtain instructor document(s)  
# call web service to obtain class documents  
# join the 2 collections
# print the output
#============================================================================================
import sys                                 #to obtain command args
import urllib.request                      #urllib.request module allows fetching of urls 
import urllib.parse                        #urllib.parse module allows you to url encode
import re                                  #for regular expression 
import json                                #to convert list of dictionary to JSON
import cgi                                 #import cgi 
import cgitb                               #import cgi traceback for error handling
cgitb.enable()

print("Content-Type: text/html \n")               #required cgi response header(for web only)

param = cgi.FieldStorage()                        #get ONLINE web parameters (if any)
lname = param.getvalue('lname')                   #get value for web param lname=

if len(sys.argv) > 1:                             #get BATCH command line arguments (if any)
    lname = sys.argv[1]                           #input argument (instructor lname)  
    
url = "https://workshop.sps.nyu.edu/~sultans/util/mongo/mongo.php"    #The mongo web service

#-------------------------------------------------------------------------------------
#encode64: encrypt user:pswd to base64
#          this is not needed if your website is not htaccess secured
#-------------------------------------------------------------------------------------
def encode64(input):
    import base64                              #encode base64

    input = input.replace('Basic','')          #remove 'Basic'
    input = input.strip()                      #trim whitespace
    bArray      = input.encode()               #convert the string to byte array
    encoded_arr = base64.b64encode(bArray)     #encode it base64
    encoded_str = encoded_arr.decode()         #convert the byte array back to string
    encoded_str = 'Basic ' + encoded_str       #re-add 'Basic'
    return(encoded_str)

authValue    = 'Basic student:123'
encryptValue = encode64(authValue)             # Basic c3R1ZGVudDoxMjM=

#-------------------------------------------------------------------------------------
#getMongoData: Retrieve Mongo data by calling a web service
#              https://workshop.sps.nyu.edu/~sultans/util/mongo/mongo.php?param
#       param: user=&pswd=&db=demo&collect=&api=native&format=native&cmd=mongoCmd
#    mongoCmd: cmd=db.instructor.find({lname:"Sultan"})
#-------------------------------------------------------------------------------------
def getMongoData(collection, query=''):

    global url

    user     = ''                                         #various parameters to supply to the web service           
    pswd     = ''           
    db       = 'demo'              
    collect  = ''              
    api      = 'native'        
    format   = 'native'

    mongoCmd = F'db.{collection}.find({query})'          #perform specific find for 1 instructor
    mongoCmd = urllib.parse.quote(mongoCmd)              #URL encode the mongoCmd

    url += F"?user={user}&pswd={pswd}&db={db}&collect={collect}&api={api}&format={format}"
    url += F"&cmd={mongoCmd}"

    try:
        req  = urllib.request.Request(url)               #create a request object
        req.add_header('Authorization', encryptValue)    #add 'Authorization: value' header (optional) 
        resp = urllib.request.urlopen(req)               #send the request
        json = resp.read()                               #read the returned data
        json = json.decode('utf-8')                      #convert it from array of bytes to string 
    except:
        print(F"<p style='color:red'>Error calling web service</p>{url}")
        sys.exit() 

    json = json.replace("ObjectId", "")                  #get rid of ObjectId
    json = json.replace("ISODate",  "")                  #get rid of ISODate
    json= '[' + json+ ']'                                #for multiple documents, make it a list
    json = re.sub("}\s*{", "},\n{", json)                #for every }{  make it },{

    try:
        obj = eval(json)                                 #convert JSON to Python list of dictionaries
    except:
        print(F"<p style='color:red'>Error converting your returned data</p>{json}")
        sys.exit()

    return(obj)        

#-------------------------------------------------------------------------------------
#join: Join 2 objects based on provided keys
#-------------------------------------------------------------------------------------
def join(objectKey1, objectKey2):

    obj1name = objectKey1[:objectKey1.index('[')]            #from start to [
    key1name = objectKey1[objectKey1.index('['):]            #from [ to end
    obj2name = objectKey2[:objectKey2.index('[')]
    key2name = objectKey2[objectKey2.index('['):]
    object1  = eval(obj1name)                                #turn the string name to a reference
    object2  = eval(obj2name)

    list_dict = []                                           #create an empty list
    
    for obj1 in object1:                                     #loop through object1
        for obj2 in object2:                                 #loop through object2            
            key1 = "obj1" + key1name                         #create a string key
            key2 = "obj2" + key2name
            key1 = eval(key1)                                #turn the string name to a reference
            key2 = eval(key2)
            if key1 == key2:                                 #join on the keys
                dict = {}                                    #create an empty dictionary
                dict.update(obj1)                            #append it with obj1
                dict.update(obj2)                            #append it with obj2
                list_dict.append(dict)                       #append the dictionary to the list  

    return(list_dict)   
#-------------------------------------------------------------------------------------
# main code
#-------------------------------------------------------------------------------------
query = ''
if lname: 
    query = F'{{ lname:"{lname}" }}'                     #{lname:"Sultan"}

instructor = getMongoData('instructor',query)            #get mongo data from instructor collection                   

query = ''
if lname:
    ssn = instructor[0]["ssn"]                            #get the instructor ssn
    query = F'{{ "inst.ssn":"{ssn}" }}'                   #{"inst.ssn":"000-02-0001"}

classes = getMongoData('class',query)                     #get mongo data from class collection

joinedObj = join("instructor['ssn']","classes['inst']['ssn']")    #join the 2 collections

#json = json.dumps(joinedObj, indent=4)                   #convert list of dictionary to JSON
json = json.dumps(joinedObj)

json = json.replace("[{", "[\n{", 1)                      #for better presentation
json = json.replace("}, {", "},\n{")                      #for better presentation

print('You can enter an instructor lastname after the <b>url?lname=<lastname></b>')
print('<br><pre>')
print(json)

print("Total Number of Rows:", len(joinedObj))




#=== link to see the python code =================================================
import os, sys
sys.path.insert(0,'/home/s/sultans/web/python/demo')
import zCode                          #import func to display the Python code
filename = os.path.abspath(__file__)  #get absolute file name 
zCode.display(filename)               #call it
#=================================================================================