def change_program(programName, com, res, intern, cost, cost_stipulations,
                   description, url):

    prog = Program.find_by_name(programName)

    if (prog == None):
        raise ValueError

    if (com != None):
        prog.comm_eng = com

    if (res != None):
        prog.research_opp = res

    if (intern != None):
        prog.internship_opp = intern

    if (cost != None):
        prog.cost = cost

    if (cost_stipulations != None):
        prog.cost_stipulations = cost_stipulations

    if (description != None):
        prog.description = description

    if (url != None):
        prog.url = url

    prog.save_to_db()
    return True
def remove_program(programName):

    prog = Program.find_by_name(programName)

    if (prog == None):
        raise ValueError

    locations = []
    for i in prog.location:
        locations.append(list(i.city, i.country))

    terms = []
    for i in prog.term:
        terms.append(i.name)

    languages = []
    for i in prog.language:
        languages.append(i.name)

    areas = []
    for i in prog.area:
        areas.append(i.name)

    change_or_remove_locations_for_program("remove", programName, locations)
    change_or_remove_terms_for_program("remove", programName, prog.term)
    change_or_remove_languages_for_program("remove", programName,
                                           prog.language)
    change_or_remove_areas_for_program("remove", programName, prog.area)

    #check for provider to see if there are any more programs and delete if not.
    prov = Providers.query.join(Programs_Providers).filter(
        (Programs_Providers.c.program_id == prog.id)).first()
    if (prov != None):
        remove_programs_from_provider(prov, list(programName))

    prog.delete()

    session.commit()

    return True


#Refrences Used:
# https://stackoverflow.com/questions/41270319/how-do-i-query-an-association-table-in-sqlalchemy
def change_or_remove_languages_for_program(change, programName, languages):

    prog = Program.find_by_name(programName)

    if (prog == None):
        raise ValueError
    if (languages == []):
        return True

    if (change == "add"):
        for i in languages:
            tempLanguage = Language.find_by_name(i)

            if (tempLanguage == None):
                tempLanguage = Language(i)
                tempLanguage.save_to_db()

            prog.add_language(tempLanguage)
            prog.save_to_db()

    elif (change == "remove"):
        for i in languages:
            tempLanguage = Language.find_by_name(i)

            if (tempLanguage == None):
                raise ValueError

            prog.remove_language(tempLanguage)
            prog.save_to_db()

            #This if statement checks to see if the removed Language has any more existing relationships
            #   If there are none, then delete the language from the database
            if (Language.query.join(Programs_Languages).filter(
                (Programs_Languages.c.language_id == tempLanguage.id
                 )).first() == None):
                db.session.delete(tempLanguage)

            prog.save_to_db()
    else:
        raise ValueError

    db.session.commit()
    return True
def change_or_remove_terms_for_program(change, programName, terms):

    prog = Program.find_by_name(programName)

    if (prog == None):
        raise ValueError
    if (terms == []):
        return True

    if (change == "add"):
        for i in terms:
            tempTerm = Term.find_by_name(i)

            if (tempTerm == None):
                tempTerm = Term(i)
                tempTerm.save_to_db()

            prog.add_term(tempTerm)
            prog.save_to_db()

    elif (change == "remove"):
        for i in terms:
            tempTerm = Term.find_by_name(i)

            if (tempTerm == None):
                raise ValueError

            prog.remove_term(tempTerm)
            prog.save_to_db()

            #This if statement checks to see if the removed Language has any more existing relationships
            #   If there are none, then delete the language from the database
            if (Term.query.join(Programs_Terms).filter(
                (Programs_Terms.c.term_id == tempTerm.id)).first() == None):
                db.session.delete(tempTerm)

            prog.save_to_db()
    else:
        raise ValueError  #If change is not "add" or "remove"

    db.session.commit()
    return True
def change_or_remove_areas_for_program(change, programName, areas):

    prog = Program.find_by_name(programName)

    if (prog == None):
        raise ValueError
    if (areas == []):
        return True

    if (change == "add"):
        for i in areas:
            tempArea = Area.find_by_name(i)

            if (tempArea == None):
                tempArea = Area(i)
                tempArea.save_to_db()

            prog.add_area(tempArea)
            prog.save_to_db()

    elif (change == "remove"):
        for i in areas:
            tempArea = Area.find_by_name(i)

            if (tempArea == None):
                raise ValueError

            prog.remove_area(tempArea)
            prog.save_to_db()

            #This if statement checks to see if the removed Language has any more existing relationships
            #   If there are none, then delete the language from the database
            if (Areas.query.join(Programs_Areas).filter(
                (Programs_Areas.c.area_id == tempArea.id)).first() == None):
                tempArea.delete()

            prog.save_to_db()
    else:
        raise ValueError

    session.commit()
    return True
def remove_program(programName):

    prog = Program.find_by_name(programName)

    if (prog == None):
        raise ValueError

    locations = []
    for i in prog.location:
        locations.append([i.city, i.country])

    terms = []
    for i in prog.term:
        terms.append(i.name)

    languages = []
    for i in prog.language:
        languages.append(i.name)

    areas = []
    for i in prog.area:
        areas.append(i.name)

    change_or_remove_locations_for_program("remove", programName, locations)
    change_or_remove_terms_for_program("remove", programName, terms)
    change_or_remove_languages_for_program("remove", programName, languages)
    change_or_remove_areas_for_program("remove", programName, areas)

    #check for provider to see if there are any more programs and delete if not.
    prov = Provider.query.join(Programs_Providers).filter(
        (Programs_Providers.c.program_id == prog.id)).first()
    if (prov != None):
        remove_programs_from_provider(prov.name, [programName])

    db.session.delete(prog)

    db.session.commit()

    return True
def remove_programs_from_provider(providerName, programs):

    prov = Provider.find_by_name(providerName)
    if (prov == None):
        raise ValueError

    for i in programs:
        tempProgram = Program.find_by_name(i)

        if (tempProgram == None):
            raise ValueError

        prov.remove_program(tempProgram)
        prov.save_to_db()

    #This if statement checks to see if the resulting Provider has any more existing relationships
    #   If there are none, then delete the provider from the database
    if (Provider.query.join(Programs_Providers).filter(
        (Programs_Providers.c.provider_id == prov.id)).first() == None):
        db.session.delete(prov)

    db.session.commit()
    return True
def create_new_program(providerName, programName, com, res, intern, cost,
                       cost_stipulations, description, url, areas, terms,
                       languages, locations):
    #-----------------------------PROVIDER RELATIONSHIP----------------------------
    # Check if the provider already exist, if it doesn't then make a new provider
    if (Provider.get_provider_id(providerName) == -1):
        prov = Provider(providerName)
        prov.save_to_db()
    else:
        prov = Provider.find_by_name(providerName)

    # Check if the program already exist, if it doesn't then make a new program
    if (Program.get_program_id(programName) == -1):
        prog = Program(programName, com, res, intern, cost, cost_stipulations,
                       description, url)
        prog.save_to_db()
    else:
        prog = Program.find_by_name(programName)

    #Add the program to the provider
    prov.add_program(prog)
    prov.save_to_db()

    #-----------------------------PROGRAM RELATIONSHIPS----------------------------
    # AREA, TERM, LANGUAGES, LOCATION

    # AREA:
    # Cyle through all area names: check to see if the area already exist in the db,
    #    if it doesn't, add it to the program and create the relationship.
    for i in areas:
        if (Area.get_area_id(i) == -1):
            tempArea = Area(i)
            tempArea.save_to_db()
        else:
            tempArea = Area.find_by_name(i)

        prog.add_area(tempArea)
        prog.save_to_db()
        #might need save to db methods

    # TERM:
    # Cyle through all term names: check to see if the term already exist in the db,
    #    if it doesn't, add it to the program and create the relationship.
    for i in terms:
        if (Term.get_term_id(i) == -1):
            tempTerm = Term(i)
            tempTerm.save_to_db()
        else:
            tempTerm = Term.find_by_name(i)

        prog.add_term(tempTerm)
        prog.save_to_db()
        #might need save to db methods

    # LANGUAGES:
    # Cyle through all term names: check to see if the term already exist in the db,
    #    if it doesn't, add it to the program and create the relationship.
    for i in languages:
        if (Language.get_language_id(i) == -1):
            tempLanguage = Language(i)
            tempLanguage.save_to_db()
        else:
            tempLanguage = Language.find_by_name(i)

        prog.add_language(tempLanguage)
        prog.save_to_db()
        #might need save to db methods

    # LOCATION:
    # Cyle through all term names: check to see if the term already exist in the db,
    #    if it doesn't, add it to the program and create the relationship.
    for i in locations:
        if (Location.get_location_id(i[0], i[1]) == -1):
            tempLocation = Location(i[0], i[1])
            tempLocation.save_to_db()
        else:
            tempLocation = Location.find_by_name(i[0], i[1])

        prog.add_location(tempLocation)
        prog.save_to_db()
def check():
    if request.method == 'GET':
        results()

    elif request.method == 'POST':
        #use post to update
        originalName = flask.request.values.get('originalName')
        addOrRemoveLang = flask.request.values.get('langPar')
        addOrRemoveTerm = flask.request.values.get('termPar')
        addOrRemoveArea = flask.request.values.get('areaPar')
        addOrRemoveLoc = flask.request.values.get('locPar')
        updateJson = flask.request.get_json(force=True)
        # each new update variable will be named and received in a simmilar fasion. It will look messy
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        #AJ, Look into using a json for this. look into the flask request api
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        #These are all the possible things that can be updated. If null, it wont be changed or removed
        print(originalName)
        print(updateJson)
        print(type(updateJson))
        updateName = None
        updateComm = None
        updateResearch = None
        updateIntern = None
        updateCost = None
        updateStipulations = None
        updateDesc = None
        updateUrl = None
        updateArea = None
        updateLang = None
        updateLocCity = None
        updateLocCountry = None
        updateTerm = None
        updateProvider = None

        if 'upname' in updateJson:
            updateName = updateJson['upname']
        if 'upcom' in updateJson:
            updateComm = updateJson['upcom']
        if 'upre' in updateJson:
            updateResearch = updateJson['upre']
        if 'upin' in updateJson:
            updateIntern = updateJson['upin']
        if 'upcos' in updateJson:
            updateCost = updateJson['upcos']
        if 'upsti' in updateJson:
            updateStipulations = updateJson['upsti']
        if 'updesc' in updateJson:
            updateDesc = updateJson['updesc']
        if 'upurl' in updateJson:
            updateUrl = updateJson['upurl']
        if 'uplang' in updateJson:
            updateLang = updateJson['uplang']
        if 'uploccit' in updateJson:
            updateLocCity = updateJson['uploccit']
        if 'uploccou' in updateJson:
            updateLocCountry = updateJson['uploccou']
        if 'upter' in updateJson:
            updateTerm = updateJson['upter']
        if 'uparea' in updateJson:
            updateArea = updateJson['uparea']
        if 'upprov' in updateJson:
            updateProvider = updateJson['upprov']
        updateAreas = updateArea.split(',')
        updateTerms = updateTerm.split(',')
        updateLanguages = updateLang.split(',')
        updateCities = updateLocCity.split(',')
        updateCountries = updateLocCountry.split(',')
        updateLocations = []
        for i in range(0, len(updateCities)):
            updateCountry.append(
                [str(updateCities[i]),
                 str(updateCountries[i])])

        #find the program
        programToModify = Program.find_by_name(originalName)
        #modify the selected values with data given
        #data will be in the variables and should be type cast as needed.
        addOrRemoveLang = flask.request.values.get('langPar')
        addOrRemoveTerm = flask.request.values.get('termPar')
        addOrRemoveArea = flask.request.values.get('areaPar')
        addOrRemoveLoc = flask.request.values.get('locPar')

        change_program(originalName, updateComm, updateResearch, updateIntern,
                       updateCost, updateStipulations, updateDesc, updateUrl)
        change_or_remove_areas_for_program(addOrRemoveArea, originalName,
                                           updateAreas)
        change_or_remove_terms_for_program(addOrRemoveTerm, originalName,
                                           updateTerms)
        change_or_remove_languages_for_program(addOrRemoveLang, originalName,
                                               updateLanguages)
        change_or_remove_locations_for_program(addOrRemoveLoc, originalName,
                                               updateLocations)

        #update modified date

        return (str(orioriginalName) + " modified")

        # if the program is successfully modified
        #return jsonify("success")
        #else, return either a message saying it failed or render the page with an error sent

    elif request.method == 'PUT':
        updateJson = flask.request.get_json(force=True)
        # each new update variable will be named and received in a simmilar fasion. It will look messy
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        #AJ, Look into using a json for this. look into the flask request api
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

        #These are all the possible things that can be updated. If null, it wont be changed or removed
        updateName = None
        updateComm = None
        updateResearch = None
        updateIntern = None
        updateCost = None
        updateStipulations = None
        updateDesc = None
        updateUrl = None
        updateArea = None
        updateLang = None
        updateLocCity = None
        updateLocCountry = None
        updateTerm = None
        updateProvider = None

        if 'upname' in updateJson:
            updateName = updateJson['upname']
        if 'upcom' in updateJson:
            updateComm = updateJson['upcom']
        if 'upre' in updateJson:
            updateResearch = updateJson['upre']
        if 'upin' in updateJson:
            updateIntern = updateJson['upin']
        if 'upcos' in updateJson:
            updateCost = updateJson['upcos']
        if 'upsti' in updateJson:
            updateStipulations = updateJson['upsti']
        if 'updesc' in updateJson:
            updateDesc = updateJson['updesc']
        if 'upurl' in updateJson:
            updateUrl = updateJson['upurl']
        if 'uplang' in updateJson:
            updateLang = updateJson['uplang']
        if 'uploccit' in updateJson:
            updateLocCity = updateJson['uploccit']
        if 'uploccou' in updateJson:
            updateLocCountry = updateJson['uploccou']
        if 'upter' in updateJson:
            updateTerm = updateJson['upter']
        if 'uparea' in updateJson:
            updateArea = updateJson['uparea']
        if 'upprov' in updateJson:
            updateProvider = updateJson['upprov']
        updateAreas = updateArea.split(',')
        updateTerms = updateTerm.split(',')
        updateLanguages = updateLang.split(',')
        updateCities = updateLocCity.splut(',')
        updateCountries = updateLocCountry.split(',')
        updateLocations = []
        for i in range(0, len(updateCities)):
            updateCountry.append([updateCities[i], updateCountries[i]])

        create_new_program(updateProvider, updateName, updateComm,
                           updateResearch, updateIntern, updateCost,
                           updateStipulations, updateDesc, updateUrl,
                           updateAreas, updateTerms, updateLanguages,
                           updateLocations)

        return "Program added"
    elif request.method == 'DELETE':

        #given the id of a program, delete it from database
        programName = flask.request.values.get('progname')

        #take in the id and use that to delete
        remove_program(programName)
        return ("Program: " + str(programName) + " Deleted")
def main():
    #------------------Remove Actions-----------------
    #Test Language: Remove Spanish from SU Buenos Aires
    Program.find_by_name("SU Buenos Aires").remove_language(Language.find_by_name("Spanish"))
    db.session.commit()

    #Test Loaction: Remove Lisbon, Portugal from SU European Cultural Exploration
    Program.find_by_name("SU European Cultural Exploration").remove_location(Location.find_by_name("Lisbon", "Portugal"))
    db.session.commit()
            #Removed the connection, but didnt remove Lisbon from the database


    #Test Area: Remove Biology from SU London
    Program.find_by_name("SU London").remove_area(Area.find_by_name("Biology"))
    db.session.commit()

    #Test Term: Remove Summer 1 from SU Amsterdam
    Program.find_by_name("SU Amsterdam").remove_term(Term.find_by_name("Summer 1"))
    db.session.commit()


    #------------------Modify Actions-----------------
    #Test removing Description from SU European Cultural Exploration
    Program.find_by_name("SU European Cultural Exploration").description = None
    db.session.commit()

    #Test Changing community engagement learning opportunity to False for SU Amsterdam
    Program.find_by_name("SU Amsterdam").comm_eng = False
    db.session.commit()

    #Test removing provider 
    Provider.find_by_name("A1").remove_program(Program.find_by_name("SU Amsterdam"))
    db.session.commit()
    


    #------------------Add Actions-----------------
    #Add Spanish and French to SU ECE
    languages = ["Spanish", "French"]
    for i in languages:
        if(Language.get_language_id(i) == -1):
            tempLanguage = Language(i)
            tempLanguage.save_to_db()
        else: 
            tempLanguage = Language.find_by_name(i)
        
        Program.find_by_name("SU European Cultural Exploration").add_language(tempLanguage)
        db.session.commit()