void CloudsClip::addKeyword(string keyword){
    if(!ofContains(additionalKeywords, keyword) &&
       !ofContains(originalKeywords, keyword))
    {
        additionalKeywords.push_back(keyword);
        keywordsDirty = true;
    }
}
void CloudsClip::revokeKeyword(string keyword){
	
//	cout << "revoking keyword " << keyword << endl;
//	cout << "	in original? " << (ofContains(originalKeywords, keyword) ? "YES" : "NO") << endl;
//	cout << "	in additional? " << (ofContains(additionalKeywords, keyword) ? "YES" : "NO") << endl;
//	cout << "	in revoked? " << (ofContains(revokedKeywords, keyword) ? "YES" : "NO") << endl;
//	
    if(!ofContains(revokedKeywords, keyword) &&
        ofContains(originalKeywords, keyword))
    {
        revokedKeywords.push_back(keyword);
        keywordsDirty = true;
    }
	else if(ofContains(additionalKeywords, keyword)){
		additionalKeywords.erase(additionalKeywords.begin() +
								 ofFind(additionalKeywords, keyword));
		keywordsDirty = true;
	}
}
void CloudsClip::setDesiredKeywords(vector<string>& desiredKeywords){
    additionalKeywords.clear();
    revokedKeywords.clear();
    
    //find all the keywords not in the original list (additonal)
    for(int i= 0; i<desiredKeywords.size();i++){
        
        //Check to see if its a special keyword
        if(! ofContains(originalKeywords, desiredKeywords[i])&& !ofContains(additionalKeywords, desiredKeywords[i]) ){
//            cout<<"adding addtional keyword : "<< desiredKeywords[i]<<" to clip "<<name<<endl;
            addKeyword(desiredKeywords[i]);
        }
    }
    
    //find all the keywords missing from the original list (rvoked)
    for(int i=0; i < originalKeywords.size() ; i++){
        if(! ofContains(desiredKeywords, originalKeywords[i])&&! ofContains(revokedKeywords, originalKeywords[i])){
//            cout<<"revoking keyword : "<< originalKeywords[i]<<" from clip "<<name<<endl;
            revokeKeyword(originalKeywords[i]);
        }
    }
    keywordsDirty =true;
}
bool CloudsTransitionController::fadedOut(){
	return ofContains(fadeOutStates, previousState);
}
bool CloudsTransitionController::fadingOut(){
	return ofContains(fadeOutStates, currentState);
}
bool CloudsClip::overlapsWithClipID(string clipID){
	return ofContains(overlappingClipIDs, clipID);
}
bool CloudsClip::overlapsWithClip(CloudsClip* clip){
	return ofContains(overlappingClipIDs, clip->getID());
}
bool CloudsClip::hasSpecialKeyword(string keyword){
	if (keyword.at(0) != '#') {
		keyword = "#"+keyword;
	}
	return ofContains(specialKeywords,keyword);
}
bool CloudsClip::hasKeyword(string keyword){
	return ofContains(getKeywords(), keyword);
}
void CloudsClip::collateKeywords(){
    
    keywords = originalKeywords;
    specialKeywords.clear();
    
    //go through and remove revoked keywords
    for (int k = 0; k<revokedKeywords.size(); k++) {
        if(ofContains(keywords, revokedKeywords[k])){
            keywords.erase(keywords.begin()+ofFind(keywords, revokedKeywords[k]));
//            cout<<"Removing keywords for clip "<<name<< " : "<< revokedKeywords[k]<<endl;
        }
    }
    
    //go through and add additional
    for (int l = 0; l < additionalKeywords.size(); l++) {
        
        if (!ofContains(keywords, additionalKeywords[l]) ){
            keywords.push_back(additionalKeywords[l]);
//            cout<<"Adding addition keywords for clip "<<name<< " : "<< additionalKeywords[l]<<endl;
        }
    }
    
    //remove special keywords from keywords -> specialKeywords
    for (int l = keywords.size() - 1 ; l >= 0; l--) {
        
        if(keywords[l].compare(0, 1, "#") == 0 && !ofContains(specialKeywords, keywords[l])){
//            cout<<"Special keywords for clip "<<name<< " : "<<keywords[l]<<". Erasing from keywords list"<<endl;
            specialKeywords.push_back(keywords[l]);
            keywords.erase(keywords.begin()+l);

        }
        else if(keywords[l][0] == '?' && !ofContains(specialKeywords, keywords[l])){
            
//           cout<<keywords[l] << " is a question in the new format. removing from keywords list and adding to questions"<< endl;
            
            //format of question topic pair is ?topic:question
            specialKeywords.push_back(keywords[l]);
            vector<string>questionTopicPair = ofSplitString(keywords[l], ":",true,true);
            ofStringReplace(questionTopicPair[0], "?", "");
            addQuestionTopicPair(questionTopicPair[0], questionTopicPair[1]);
            keywords.erase(keywords.begin() + l);
        }
    }
    
	hasProjectExample = false;
	projectExampleTitle = "";
	for(int i = 0; i < specialKeywords.size(); i++){
		if(specialKeywords[i].find("pe?") != string::npos){
			vector<string> exampleProject = ofSplitString(specialKeywords[i], "?");
			if(exampleProject.size() != 2){
				ofLogError("CloudsClip::collateKeywords") << "Clip " << getLinkName() << " doesn't have a specific example tagged";
			}
			else {
				projectExampleTitle = exampleProject[1];
				hasProjectExample = true;
//				cout << "Found project example " << projectExampleTitle << " for clip " << getLinkName() << endl;
			}
			break;
		}
	}
    keywordsDirty = false;
}