#include "grafPlayerApp.h"

//--------------------------------------------------------------
grafPlayerApp::grafPlayerApp(){


}

grafPlayerApp::~grafPlayerApp(){


}
//--------------------------------------------------------------
void grafPlayerApp::setup(){

	mode			= PLAY_MODE_LOAD;
	screenW			= 1024;
	screenH			= 768;
	lastX			= 0;
	lastY			= 0;
	bShowPanel		= false;
	bRotating		= false;
	bShowName		= false;
	bShowTime		= false;
	bUseFog			= true;
	bUseMask		= true;
	bTakeScreenShot = false;
	bUseGravity		= true;
	prevStroke		= 0;
	
	currentTagID	= 0;
	waitTime		= 2.f;
	waitTimer		= waitTime;
	rotationY		= -45;
	tagMoveForce	= .1;
	tagPosVel.set(0,0,0);
	myTagDirectory = TAG_DIRECTORY;
	
	fontSS.loadFont("fonts/frabk.ttf",9);
	fontS.loadFont("fonts/frabk.ttf",14);
	fontL.loadFont("fonts/frabk.ttf",22);
	imageMask.loadImage("images/mask.jpg");
	
	float FogCol[3]={0,0,0};
    glFogfv(GL_FOG_COLOR,FogCol);
    glFogi(GL_FOG_MODE, GL_LINEAR);
    glFogf(GL_FOG_DENSITY, 0.05f);
	fogStart = 370;
    fogEnd   = 970;
	
	ofxXmlSettings xml;
	xml.loadFile( ofToDataPath("settings/directorySettings") );
	myTagDirectory = xml.getValue("directory", TAG_DIRECTORY);

	//aint loading from xml... gotta bypass to test..
	//myTagDirectory = "tags/Rudy/";

	
	setupContolPanel();
	updateConrolPanel();
	
	preLoadTags();
	particleDrawer.setup(screenW,screenH);

}

static float lastTime = 0.f;

//--------------------------------------------------------------
void grafPlayerApp::update(){

	dt  = ofGetElapsedTimef()-lastTime;
	lastTime  = ofGetElapsedTimef();
	
	if( mode == PLAY_MODE_LOAD )
	{
		loadTags();
	}
	else if( mode == PLAY_MODE_PLAY )
	{
		if( tags.size() > 0 && drawer.bSetupDrawer)
			drawer.setup( &tags[currentTagID], tags[currentTagID].distMax );

		if( tags.size() > 0 && !myTagPlayer.bDonePlaying )					// normal play, update tag
		{
			myTagPlayer.update(&tags[currentTagID]);
		
		}else if( !myTagPlayer.bPaused && myTagPlayer.bDonePlaying && waitTimer > 0)			   // pause time after drawn, before fades ut
		{
			waitTimer -= dt;
		}
		else if ( !myTagPlayer.bPaused && myTagPlayer.bDonePlaying && (drawer.alpha > 0 || particleDrawer.alpha > 0))			  // fade away, dissolve
		{
			drawer.transition(dt,.015);
			if( bUseGravity ) particleDrawer.fall(dt);
			if(particleDrawer.alpha  > 0 ) particleDrawer.alpha -= .5*dt;
			
		}
		else if (  !myTagPlayer.bPaused && myTagPlayer.bDonePlaying )							// set next tag
		{
			resetPlayer(1);
		}
	
		//---- update the particle field
		int lastStroke = myTagPlayer.getCurrentStroke();
		int lastPoint = myTagPlayer.getCurrentId();
		
		if( prevStroke != lastStroke ) myTagPlayer.bReset = true; 
		if( lastPoint <= 0 ) myTagPlayer.bReset = true;
		if( tags[currentTagID].myStrokes[ lastStroke].pts.size()-1 == lastPoint ) myTagPlayer.bReset = true;
		
		particleDrawer.update( myTagPlayer.getCurrentPoint(),myTagPlayer.getVelocityForTime(&tags[currentTagID]),  dt,  myTagPlayer.bReset);
		
		myTagPlayer.bReset = false; // important so no particle error on first stroke
		prevStroke		= myTagPlayer.getCurrentStroke();
		//---
		
		
		// update rotation
		if(bRotating) rotationY += .65*dt;
		
		// update pos / vel
		tags[currentTagID].position.x += tagPosVel.x;
		tags[currentTagID].position.y += tagPosVel.y;
		
		tagPosVel.x -= .1*tagPosVel.x;
		tagPosVel.y -= .1*tagPosVel.y;
		
		
		
	}
	
	if( bShowPanel ) updateConrolPanel();
	
}


//--------------------------------------------------------------
void grafPlayerApp::draw(){

	ofEnableAlphaBlending();
	
	ofSetColor(255,255,255,255);

	if( mode == PLAY_MODE_LOAD )
	{
	}
	else if( mode == PLAY_MODE_PLAY )
	{
	
		
		ofEnableAlphaBlending();
		
		glPushMatrix();
		
		
			if( bUseFog )
			{
				glFogf(GL_FOG_START, fogStart );
				glFogf(GL_FOG_END, fogEnd );
				glEnable(GL_FOG);				
			}
		
			glTranslatef(screenW/2, screenH/2, 0);
		
			glScalef(tags[currentTagID].position.z,tags[currentTagID].position.z,tags[currentTagID].position.z);
		
			glTranslatef(tags[currentTagID].position.x,tags[currentTagID].position.y,0);
			

			
			glPushMatrix();
		
				glRotatef(tags[currentTagID].rotation.x,1,0,0);
				glRotatef(tags[currentTagID].rotation.y+rotationY,0,1,0);
				glRotatef(tags[currentTagID].rotation.z,0,0,1);
		
				glTranslatef(-tags[currentTagID].min.x*tags[currentTagID].drawScale,-tags[currentTagID].min.y*tags[currentTagID].drawScale,-tags[currentTagID].min.z);
				glTranslatef(-tags[currentTagID].center.x*tags[currentTagID].drawScale,-tags[currentTagID].center.y*tags[currentTagID].drawScale,-tags[currentTagID].center.z);
		
				glDisable(GL_DEPTH_TEST);
				particleDrawer.draw(myTagPlayer.getCurrentPoint().z,  screenW,  screenH);
				
				glEnable(GL_DEPTH_TEST);
		
				glPushMatrix();
					glScalef( tags[currentTagID].drawScale, tags[currentTagID].drawScale, 1);
					drawer.draw( myTagPlayer.getCurrentStroke(), myTagPlayer.getCurrentId() );
				glPopMatrix();
		
				glPushMatrix();
					glScalef( tags[currentTagID].drawScale, tags[currentTagID].drawScale, 1);
					//drawer.drawBoundingBox( tags[currentTagID].min, tags[currentTagID].max, tags[currentTagID].center );
				glPopMatrix();
		
			glPopMatrix();
		
			
		
		glPopMatrix();
		
		
		glDisable(GL_DEPTH_TEST);
		glDisable(GL_FOG);
		

	
	
	}
	
	if(bUseMask)
	{
		ofEnableAlphaBlending();
		glBlendFunc(GL_DST_COLOR, GL_ZERO);
		imageMask.draw(0,0,ofGetWidth(),ofGetHeight());
	}
	
	
	if( mode == PLAY_MODE_PLAY )
	{
		ofSetColor(255,255,255,255);
		if( bShowName && tags.size() > 0 ) fontS.drawString( tags[ currentTagID ].tagname, 10,ofGetHeight()-30 );
		if( bShowTime && tags.size() > 0 )
		{
			float time = myTagPlayer.getCurrentTime();
			float wd = fontL.stringWidth( ofToString( time,0) ) / 10.f;
			wd = 10*(int)(wd);
			
			fontL.drawString(ofToString(time,2), ofGetWidth()-wd-70, ofGetHeight()-30);
		}
	
	}


	ofEnableAlphaBlending();
	if(bShowPanel){
		panel.draw();
		fontSS.drawString("x: toggle control panel  |  p: pause/play  |  s: screen capture  |  m: toggle mouse  |  f: toggle fullscreen  |  h: toggle home  |  arrows: next/prev  |  esc: quit", 90, ofGetHeight()-50);
		fontSS.drawString("left mouse: alter position  |  left+shift mouse: zoom  |  right mouse: rotate y  |  right+shift mouse: rotate x", 220, ofGetHeight()-30);

	}
	

	// screenshots
	if(bTakeScreenShot)
	{
		imgsaver.grabScreen(0,0,ofGetWidth(),ofGetHeight() );
		
		dirLister.setPath( ofToDataPath(myTagDirectory + tags[currentTagID].tagname + "/", true));
		dirLister.setExtensionToLookFor("png");
		int num = dirLister.getNumberOfFiles();
		imgsaver.saveThreaded( myTagDirectory + tags[currentTagID].tagname + "/"+tags[currentTagID].tagname+"_"+ofToString(num+1)+".png");
		
		bTakeScreenShot = false;
	}
	
}

/*
 * Take in a Flickr rest style api url that doesn't require
 * authenticaiton and an api_key
 */
/*std::vector<std::string> getFlickrImageUrls(
											const std::string& rest_url, const std::string& api_key)
{
    // Get REST style xml as string from flickr
    std::auto_ptr<std::istream>
    pStr(URIStreamOpener::defaultOpener().open(
											   rest_url +  "&api_key=" + api_key));
    std::string str;
    StreamCopier::copyToString(*pStr.get(), str);
	
    // Set up XML Parser
    DOMParser parser;
    Document* pDoc = parser.parseString(str);
    NodeIterator it(pDoc, NodeFilter::SHOW_ELEMENT);
    Node* pNode = it.nextNode();
    NamedNodeMap *nnm;
    std::vector<std::string> urls;
    std::string current_url;
    while (pNode) {
        nnm = pNode->attributes();
        current_url = makeFlickrUrl(
									nnm->getNamedItem("farm"),
									nnm->getNamedItem("server"),
									nnm->getNamedItem("id"),
									nnm->getNamedItem("secret"));
        if (current_url.length() > 0)
            urls.push_back(current_url);
        pNode = it.nextNode();
    }
    nnm->release();
    return urls;
}*/


/* main */
/*int main(int argc, char** argv)
{
    HTTPStreamFactory::registerFactory();
    std::vector<std::string>
	img_urls = getFlickrImageUrls(REST_URL, API_KEY);
    for (std::vector<std::string>::const_iterator
		 iter = img_urls.begin();
		 iter != img_urls.end(); ++iter) {
        std::cout << *iter << std::endl;
    }
}*/

void grafPlayerApp::getGuidValues( const std::string& result, std::vector<int>* dest ){
	//std::vector<int> intList;
	
	try
	{
		TiXmlDocument doc;
		if( !doc.Parse( result.c_str()) )
		{
			cout << "Error: could not load string" << endl;
		}
		
		TiXmlElement* element;
		TiXmlElement* child;
		TiXmlNode* root;
		
		//get root element 'TodoList', set to hRoot
		root = doc.FirstChildElement();
		if( !root )
		{
			cout << "no valid root!" << endl;
		}
		
		TiXmlElement* channelElem = root->FirstChildElement("channel");
		cout << "channel: " << channelElem->Value() << endl;
		
		element = root->FirstChildElement("channel");
		
		int count = 0;
		for( element=element->FirstChildElement("item"); element; element = element->NextSiblingElement() )
		{
			TiXmlElement* pCur = element->FirstChildElement("guid");
			if(pCur)
			{
				std::cout << "guid: " << pCur->Value() << "   " << pCur->GetText() << std::endl;
				
				int i = -9999;
				std::istringstream val( pCur->GetText() );
				val >> i;
				dest->push_back( i );
			}
		}
	}
	catch( Exception& e )
	{
		std::cerr << e.displayText() << std::endl;
	}
}

bool grafPlayerApp::makeDirectory(string dirPath, bool bRelativeToData = true){
	if( bRelativeToData ) dirPath = ofToDataPath(dirPath);
	
	File myFile(dirPath);
	bool success = false;
	try{
		success = myFile.createDirectory();
	}catch( Poco::Exception &except ){
		ofLog(OF_LOG_ERROR, "makeDirectory - directory could not be created");
		return false;
	}
	
	if(!success)ofLog(OF_LOG_WARNING, "makeDirectory - directory already exists");
	
	return success;
}

void grafPlayerApp::loadTagsFromRSS( const std::string &thisword ) {
	try {
	//	std::string thisword = "Rudy"; 
		
		//get RSS
		std::string thisuri = "http://www.tpolm.org/~ps/crawl/gmlrss.php?keywords=";
		thisuri.append(thisword);
		std::cout << thisuri << std::endl;
		URI uri(thisuri);
		std::string path(uri.getPathAndQuery());
		if (path.empty()) path = "/";
		
		HTTPClientSession session(uri.getHost(), uri.getPort());
		HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
		session.sendRequest(req);
		HTTPResponse res;
		istream& rs = session.receiveResponse(res);
		std::cout << res.getStatus() << " " << res.getReason() << std::endl;
		
		//parse RSS for guid 
		std::string result;
		StreamCopier::copyToString(rs, result);
		std::vector<int> dest;
		getGuidValues( result, &dest );
		
		//create sub directory
		std::string thisdir = myTagDirectory;
		thisdir.append(thisword);
		makeDirectory( thisdir );
		
		//get all guids .gml into subdirectory
		for (int i = 0; i < dest.size(); i++) {
			
			std::ostringstream thisuri;
			thisuri << "http://000000book.com/data/" << dest[i] << ".gml";
			URI uri(thisuri.str());
			std::string path(uri.getPathAndQuery());
			if (path.empty()) path = "/";
			HTTPClientSession session(uri.getHost(), uri.getPort());
			HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
			session.sendRequest(req);
			HTTPResponse res;
			istream& rs = session.receiveResponse(res);
			std::cout << res.getStatus() << " " << res.getReason() << std::endl;
			//std::string result;
			//StreamCopier::copyToString(rs, result);
			
			//save to disk
			ofstream myfile;
			std::ostringstream filename;
			filename << thisdir << "/" << dest[i];
			makeDirectory( filename.str() ); //seems gml player easierly looks for tags/hotword/filename-1/filename-1.gml instead of tags/hotword/*.gml
			filename << "/" << dest[i] << ".gml";
			myfile.open (ofToDataPath(filename.str()).c_str());
			StreamCopier::copyStream(rs, myfile);
			myfile.close();
			
		}
		
		//reload tags
		//hacked from preLoadTags()
			filesToLoad.clear();
			filenames.clear();
			totalToLoad = 0;
			tags.clear();
			
			vector<string> dirs;
			dirLister.setPath( ofToDataPath(myTagDirectory+thisword,true) );
			dirLister.findSubDirectories(dirs);
			
			for( int i = 0; i < dirs.size(); i++)
			{
				dirLister.setPath( ofToDataPath(myTagDirectory+thisword+"/"+dirs[i]+"/",true) );
				dirLister.setExtensionToLookFor("gml");
				int num = dirLister.getNumberOfFiles();
				if( num > 0 )
				{
					filenames.push_back(dirs[i]);
					filesToLoad.push_back(  ofToDataPath(myTagDirectory+thisword+"/"+dirs[i]+"/"+dirs[i]+".gml") );
					
					tags.push_back( grafTagMulti() );
					int toLoad = tags.size()-1;
					
					gIO.loadTag( filesToLoad[ toLoad ], &tags[ toLoad ]);
					tags[ toLoad ].tagname = filenames[ toLoad ];
					
					smoother.smoothTag(4, &tags[ toLoad ]);
					tags[toLoad].average();
					tags[toLoad].average();
					
				}
			}

		
	}
	catch (Exception& exc)
	{
		std::cerr << exc.displayText() << std::endl;
		//exit();
	}
		
}


//--------------------------------------------------------------
void grafPlayerApp::keyPressed  (int key){


	
    switch(key){

  		case 'x': bShowPanel=!bShowPanel; break;
		case 'p': 
			myTagPlayer.bPaused = !myTagPlayer.bPaused;
			bRotating = !myTagPlayer.bPaused;
			panel.setValueB("ROTATE",bRotating);
			panel.setValueB("PLAY",!myTagPlayer.bPaused);
			break;
			
			
		case OF_KEY_RIGHT:  resetPlayer(1); break;
        case OF_KEY_LEFT:   resetPlayer(-1); break;
		
		case 's': bTakeScreenShot = true; break;
			
	
		default:
  			break;

  }



}

//--------------------------------------------------------------
void grafPlayerApp::keyReleased(int key){

}

//--------------------------------------------------------------
void grafPlayerApp::mouseMoved(int x, int y ){

	lastX   = x;
	lastY   = y;
}

//--------------------------------------------------------------
void grafPlayerApp::mouseDragged(int x, int y, int button){

	if( bShowPanel && !panel.minimize) 
	{
		panel.mouseDragged(x,y,button);
	}
	else{
		if( button == 0 )
		{
			if(!bShiftOn)
			{
				tagPosVel.x +=  tagMoveForce * (x-lastX);
				tagPosVel.y +=  tagMoveForce * (y-lastY);
			}else if(tags.size() > 0){
				tags[currentTagID].position.z += .01 * (y-lastY);
				tags[currentTagID].position.z = MAX(tags[currentTagID].position.z,.01);
			}
			
		
		}else{
			if( tags.size() > 0 && !bShiftOn) tags[currentTagID].rotation.y += (x-lastX);
			else if( tags.size() > 0 && bShiftOn) tags[currentTagID].rotation.x += (y-lastY);
		}
	}	
	
	
	lastX   = x;
	lastY   = y;

}

//--------------------------------------------------------------
void grafPlayerApp::mousePressed(int x, int y, int button){

    if( bShowPanel ) panel.mousePressed(x,y,button);

}

//--------------------------------------------------------------
void grafPlayerApp::mouseReleased(int x, int y, int button){

	if( bShowPanel && !panel.minimize) 
	{
		panel.mouseReleased();
	}
	 


}

//--------------------------------------------------------------
void grafPlayerApp::resetPlayer( int next)
{
	if(tags.size() <= 0 ) return;
	
	myTagPlayer.reset();
	
	nextTag(next);
	
	drawer.setup( &tags[currentTagID], tags[currentTagID].distMax );
	
	particleDrawer.reset();
	
	waitTimer = waitTime;
	
	rotationY = 0;
	
	tagPosVel.set(0,0,0);
	
	prevStroke = 0;

	
}
//--------------------------------------------------------------
void grafPlayerApp::nextTag(int dir)
{
	
	if(dir==1)
	{
		currentTagID++;
		currentTagID %= tags.size();
	}
	else if(dir==-1){
		currentTagID--;
		if(currentTagID < 0 ) currentTagID = tags.size()-1;
	}
		
	
}
//--------------------------------------------------------------
void grafPlayerApp::loadTags()
{
	if( tags.size() < totalToLoad )
	{
		tags.push_back( grafTagMulti() );
		int toLoad = tags.size()-1;
		
		gIO.loadTag( filesToLoad[ toLoad ], &tags[ toLoad ]);
		tags[ toLoad ].tagname = filenames[ toLoad ];
		
		smoother.smoothTag(4, &tags[ toLoad ]);
		tags[toLoad].average();
		tags[toLoad].average();
	}
	else{
		mode = PLAY_MODE_PLAY;
		resetPlayer(0);
	}
	
}
//--------------------------------------------------------------
void grafPlayerApp::preLoadTags()
{
	filesToLoad.clear();
	filenames.clear();
	totalToLoad = 0;
	
	vector<string> dirs;
	dirLister.setPath( ofToDataPath(myTagDirectory,true) );
	dirLister.findSubDirectories(dirs);
	
	for( int i = 0; i < dirs.size(); i++)
	{
		dirLister.setPath( ofToDataPath(myTagDirectory+dirs[i]+"/",true) );
		dirLister.setExtensionToLookFor("gml");
		int num = dirLister.getNumberOfFiles();
		if( num > 0 )
		{
			filenames.push_back(dirs[i]);
			filesToLoad.push_back(  ofToDataPath(myTagDirectory+dirs[i]+"/"+dirs[i]+".gml") );
		}
	}
	
	
	dirs.clear();
	dirLister.setPath( ofToDataPath(myTagDirectory,true) );
	dirLister.setExtensionToLookFor( "gml" );
	dirLister.getFileNames(dirs);
	
	for( int i = 0; i < dirs.size(); i++)
	{
		filesToLoad.push_back( ofToDataPath(myTagDirectory+dirs[i]) );
		
		string name = dirs[i];
		int endgml = name.find(".gml");
		if( endgml >= 0 )
			name.erase( endgml,name.size() );
		
		filenames.push_back(name);
	}
	
	totalToLoad = filesToLoad.size();
}
//--------------------------------------------------------------
void grafPlayerApp::setupContolPanel()
{
	
	panel.setup("Graffiti Analysis", 20, 20, 300, 500);
	panel.addPanel("App Settings", 1, false);
	panel.addPanel("Draw Settings", 1, false);
	
	
	//---- application sttings
	panel.setWhichPanel("App Settings");
	panel.addToggle("Play / Pause", "PLAY", true);
	panel.addToggle("Rotate", "ROTATE", true);
	panel.addToggle("Display filename", "SHOW_NAME", true);
	panel.addToggle("Display time", "SHOW_TIME", true);
	panel.addToggle("FullScreen", "FULL_SCREEN", false);
	panel.addToggle("Use Fog", "USE_FOG", false);
	panel.addSlider("Fog Start","FOG_START",fogStart,-2000,2000,true);
	panel.addSlider("Fog End","FOG_END",fogEnd,-2000,2000,true);
	
	panel.setWhichPanel("Draw Settings");
	panel.addSlider("Line Alpha","LINE_ALPHA",.92,0,1,false);
	panel.addSlider("Outline Width","LINE_WIDTH",2,1,10,false);
	panel.addSlider("Line Scale","LINE_SCALE",.05,0,.1,false);
	panel.addSlider("Particle Size","P_SIZE",2,0,10,false);
	panel.addSlider("Particle Alpha","P_ALPHA",.75,0,1,false);
	panel.addSlider("Particle Damping","P_DAMP",.15,0,.25,false);
	panel.addSlider("Number Particles","P_NUM",1,0,4,true);
	//panel.addSlider("Wait time","WAIT_TIME",1,0,4,true);
	panel.addToggle("Use gravity", "USE_GRAVITY", true);
	panel.addToggle("Use edge mask", "USE_MASK", false);
	panel.loadSettings("settings/appSettings.xml");
}

//--------------------------------------------------------------
void grafPlayerApp::updateConrolPanel()
{
	panel.update();
	myTagPlayer.bPaused = !panel.getValueB("PLAY");
	bRotating = panel.getValueB("ROTATE");
	bShowName = panel.getValueB("SHOW_NAME");
	bShowTime = panel.getValueB("SHOW_TIME");
	if( panel.getValueB("FULL_SCREEN") )
	{
		panel.setValueB("FULL_SCREEN",false);
		ofToggleFullscreen();
	}
	
	bUseFog = panel.getValueB("USE_FOG");
	fogStart = panel.getValueI("FOG_START");
	fogEnd = panel.getValueI("FOG_END");
	
	drawer.setAlpha(panel.getValueF("LINE_ALPHA"));
	drawer.lineWidth = panel.getValueF("LINE_WIDTH");
	
	drawer.setLineScale( panel.getValueF("LINE_SCALE") );
	
	particleDrawer.setParticleSize( panel.getValueF("P_SIZE") );
	particleDrawer.setDamping( panel.getValueF("P_DAMP") );
	particleDrawer.particle_alpha = panel.getValueF("P_ALPHA") ;
	particleDrawer.numXtras = panel.getValueI("P_NUM");
	bUseGravity = panel.getValueB("USE_GRAVITY");
	bUseMask = panel.getValueB("USE_MASK");
	
}

string grafPlayerApp::getCurrentTagName()
{
	if(tags.size() <= 0 ) return " ";
	else if( mode == PLAY_MODE_LOAD) return tags[tags.size()-1].tagname;
	else return tags[currentTagID].tagname;
}

