//////// Reference 01
// IDEA 9101 - week 4 - example - Receiving MQTT, by Luke Hespanhol
// A template used in IDEA lab, to allow p5.js sketch to receive message via MQTT
////////

//////// Reference 02
// Mist, by 平金凌 from openprocessing
// The example Draws many ellipses to simulate the fog effect
// We didn't use the original code directly, instead, we rearrange the original code into a class
// https://openprocessing.org/sketch/1573235
//////// 

//////// Reference 03
// Starry Night, by Russell G Brewer from openprocessing
// The example creates the particle system of stars, and use the frameCount value to create the shooting star effect
// We modified and adapted from this example
// https://openprocessing.org/sketch/510610
//////// 

//////// Reference 04
// Noise Wave, by Daniel Shiffman from p5.js example
// The example Uses Perlin Noise to generate a wave-like pattern
// We modified the example as the original example doesn't have the actual depth of water
// To better adapt to our project, we add getHeight, decrease and increase function
// https://p5js.org/examples/math-noise-wave.html
//////// 

//////// Reference 05
// JAPAN o'clock, by Shio from openprocessing
// The example Uses particle system to create bouncing flowers, the pattern of flowers will change based on seasons
// We only use the flower's particle system of this example. We adapted from it and added a bounce value that accepts users' control
// https://openprocessing.org/sketch/810159
//////// 

//////// Reference 06
// Interactive Environment Project, by Joseph Penders from openprocessing
// The example draws an interactive city with moving clouds, birds, hot ballon, and boat
// We only use code of drawing single bird in this example. We rearrange it into Birds Class
// https://openprocessing.org/sketch/1105097
//////// 

//////// Reference 07
// Star function, from p5.js example
// The example draws stars in different forms
// We refer to this example to create the background star (pentagram)
// https://p5js.org/examples/form-star.html
//////// 

//////// Reference 08
// Flower, by Yusuke Sasaki from openprocessing
// The example draws a flower
// We only use the output image of this example
// https://openprocessing.org/sketch/1105097
//////// 

//////// Inspiration 01
// RainyNight, by Sehyeon from openprocessing
// Create the rainfall effect
// We didn't use the original code, instead, we learn from the code so that we know what interesting 
// interactions can be achieved. We created our own version of rainfall. 
// https://openprocessing.org/sketch/1553841
//////// 


document.addEventListener('touchstart', function (e) {
	document.documentElement.style.overflow = 'hidden';
});

document.addEventListener('touchend', function (e) {
	document.documentElement.style.overflow = 'auto';
});


//////////////////////////////////////////////////
//FIXED SECTION: DO NOT CHANGE THESE VARIABLES
//////////////////////////////////////////////////
var HOST = window.location.origin;
var socket;

////////////////////////////////////////////////////
// CUSTOMIZABLE SECTION - BEGIN: ENTER OUR CODE HERE
////////////////////////////////////////////////////


// Defining image variables
// Background image and the city's image
var img;
var bg;

// Defining raindrops variable
let raindrops = [];
let raindropSystem;
let speedOfRaindrop;
let windOfRaindrop;
const RAINDROP_MAX_NUM = 50;
const RAINDROP_BASIC_DENSITY = 0.1;
const RAINDROP_DENSITY_LERPRATE = 0.02;

// Defining shooting stars variables
let myShootingStar;
let shootingStars = [];

// Defining mists (fog) variables
let mists = [];
// The maximum number of mists
const NUM = 500;

// Set Sounds Array
// There are four sound effects are used
let sounds = [];
let currentSound;

// Max number of 200 stars
const STARS_MAX_NUM = 200;
const STARS_BASIC_DENSITY = 0.1;
const STARS_DENSITY_LERPRATE = 0.02;

// Ocean variables
let theOcean;

// Flowers variables
let flowerImg;
let lists = [];
let pNum = 100; // number of flowers
let touching = false;
let size;

// Bird variables
let bird = [];


////////////////////////////////////////////////////
/////////////////////// MQTT ///////////////////////
let userInputRaindropDensity;
let userInputPower;
let userInputFog;
let jumpPowerOfFlowers;

// Mode Selection
let rainMode_Received = false;
let fogMode_Received = false;
let flowerMode_Received = false;
let starMode_Received = false;

let star = [];



////////////////////////////
// PRELOAD FUNCTION
////////////////////////////
function preload() {
	// Flower image
	flowerImg = loadImage('assets/flower.png');
	// Preload four sound effects
	for (let i = 0; i < 4; i++) {
		sounds[i] = loadSound('assets/music' + i + '.mp3');
	}
	// Shanghai city image
	img = loadImage("assets/ShangHai.png");
	// Background gradient color image
	bg = loadImage("assets/backgroundSky.png");
}

////////////////////////////
// SETUP FUNCTION
////////////////////////////
function setup() {

	createCanvas(1280, 720);
	background(0);
	setupMqtt();


	for (let sound of sounds) {
		sound.loop();
		sound.pause();
	}

	currentSound = sounds[0];

	// This are the initial pre-defined values
	// These values will change according to users' gesture duration input
	userInputRaindropDensity = 0.05;
	windOfRaindrop = 10;
	speedOfRaindrop = 3;
	userInputPower = 0;
	userInputFog = 1;
	jumpPowerOfFlowers = 3;
	
	// Define flower size
	size = Math.floor(min(windowWidth, windowHeight) * 0.9);
	// Setup 100 flowers
	for (let i = 0; i < pNum; i++) {
		p = new P();
		lists.push(p);
	}

	// Setup the rain and ocean
	raindropSystem = new RaindropSystem();
	raindropSystem.setup();
	theOcean = new ocean();

	// Setup shooting star
	myShootingStar = new ShootingStar();
	for (var i = 0; i < 200; i++) {
		shootingStars[i] = new SingleStar();
	}
	// Setup mists (fog)
	for (let i = 0; i < NUM; i++) {
		mists[i] = new Mist(random(width), random(height));
	}

	// Setup birds
	for (let i = 0; i < 5; i++) {
		bird[i] = new Birds();
	}
	// Background pentagrams
	star_Def();

	createCanvas(img.width, img.height);
	// create array from image
	img.loadPixels();

}



////////////////////////////
// SWITCH BETWEEN FOUR SOUND EFFECTS FUNCTION
////////////////////////////
function switchSound(id) {
	if (id >= sounds.length) return;

	currentSound.pause();
	currentSound = sounds[id];
	currentSound.play();
}


////////////////////////////
// DRAW FUNCTION
////////////////////////////
function draw() {
	background(0, 45);

	// Image of the gradient background
	// Use tint will make the background transparent, but the program will be running slowly
	push();
	tint(255, 100);
	image(bg, 0, 0);
	pop();
	// Image of Shanghai
	image(img, 0, 0);

	// Display background birds
	for (let i = 0; i < bird.length; i++) {
		bird[i].display();
		bird[i].move();
	}

	// Display default background pentagrams
	star_Display();

	// Display the ocean
	theOcean.display();

	// 1 - Display RainMode 
	if (rainMode_Received && fogMode_Received == false && starMode_Received == false && flowerMode_Received == false) {
		displayRain();
		fogMode_Received = false;
		starMode_Received = false;
		flowerMode_Received = false;
	}

	// 2 - Display FlowerMode
	if (flowerMode_Received && fogMode_Received == false && starMode_Received == false && rainMode_Received == false) {
		displayFlower();
		fogMode_Received = false;
		starMode_Received = false;
		rainMode_Received = false;
	}

	// 3 - Display FogMode
	if (fogMode_Received) {
		displayFog();
	}

	// 4 - Display ShootingStar
	if (starMode_Received) {
		displayStar();

	}
}

////////////////////////////
// DISPLAY FOG, STAR, FLOWER, RAIN FUNCTION
////////////////////////////
// Organize all fog code into this function, and call it in the draw function
function displayFog() {

	for (let i = mists.length - 1; i > -1; i--) {
		mists[i].show();
		mists[i].move();
	}
}
// Organize all star code into this function, and call it in the draw function
function displayStar() {

	myShootingStar.setDensity(userInputRaindropDensity);
	myShootingStar.render();
}
// Organize all flower code into this function, and call it in the draw function
function displayFlower() {

	if (touching && userInputPower < 3) {
		userInputPower += 0.1;
	}

	for (let i = 0; i < lists.length; i++) {
		lists[i].act();
	}
}

function displayRain() {

	// Use duration to control the number of raindrops
	raindropSystem.setDensity(userInputRaindropDensity);
	console.log("density: " + userInputRaindropDensity);
	raindropSystem.render();

}


////////////////////////////
// MIST CLASS
////////////////////////////
// The way of drawing mist (or fog) is inspired by Reference 02 - Mist, created by 平金凌
// We didn't use the original code directly, instead, we rearrange the original code into a class
// But the logic (i.e., draw 500 ellipses and adjust their alpha value to display fog) is the same
// In our version, the alpha value of ellipses is controlled by users
class Mist {
	constructor(x, y) {
		this.pos = createVector(x, y);
		this.vel = createVector(random(-width / 100, width / 100), random(-width / 100, width / 100));
		this.diameter = 600;
		// this.lifespan = 4;
	}

	move() {
		if (this.pos.x - 100 < 0 || this.pos.x + 100 > width) {
			this.vel.x *= -1;
		}
		if (this.pos.y + 100 < 0 || this.pos.y - 100 > height) {
			this.vel.y *= -1;
		}
	}

	show() {
		// this.lifespan = this.lifespan - 0.04;
		noStroke();
		fill(255, 255, 255, userInputFog);
		ellipse(this.pos.x, this.pos.y, this.diameter, this.diameter);
		this.pos.add(this.vel);
	}

}


////////////////////////////
// PARTICLE SYSTEM - SHOOTING STAR CLASS
////////////////////////////
// This function is inspired and adapted from Reference 03 - Starry Night, created by Russell G Brewer
// Our main modifications are: 
// (1) allow users to control the density of stars
// (2) allow users to shoot stars instead of using frameCount value to control the shooting star

// Firstly, we created SingleStar function to store the values of single star
// Then, in the ShootingStar function, we add setDensity function which will receive the MQTT message (durationValue) to decide the density of stars
// We also use this value to shoot stars and determine the number of shooting stars
function ShootingStar() {
	// setup 200 shooting stars
	this.maxNum = STARS_MAX_NUM;
	// density variables
	this.densityThreshold = 0;
	this.targetDensityThreshold = 0;
	this.basicDensity = STARS_BASIC_DENSITY;
	this.densityLerprate = STARS_DENSITY_LERPRATE;

	// render function (display every single star in the SingleStar class)
	this.render = function () {
		this.densityThreshold = lerp(
			this.densityThreshold,
			this.targetDensityThreshold,
			this.densityLerprate
		);

		for (let i = this.maxNum - 1; i > -1; i--) {
			// only when meet the density requirement will display 
			if (shootingStars[i].density < this.densityThreshold) {
				// when stars are off the screen, delete them from the array 
				if (shootingStars[i].render() === false) {
					shootingStars.splice(i, 1);

					shootingStars.push(new SingleStar());
				}
				// test 
				// if (mouseIsPressed == true) {
				//   shootingStars[i].shoot(); // let stars = random(shootingStars);
				// }
			}
		}
	};

	// Density function
	// durationValue receives the MQTT message
	// users' gesture duration value (the time touched on the screen) will determine this value
	this.setDensity = function (durationValue) {
		this.targetDensityThreshold = lerp(this.basicDensity, 1, durationValue);
	};
}


////////////////////////////
// SINGLE STAR CLASS
////////////////////////////
// Modification of example code (Reference 03) starts from here
function SingleStar() {
	this.x = random(width);
	this.y = random(height);
	this.r = random(1, 6);
	this.alpha = 255;
	this.xoff = 0;
	this.yoff = 0;
	this.shooting = false;
	this.density = random(1);

	this.render = function () {
		// shoot the star. A little alpha to fade it out.
		if (this.shooting) {
			this.x += this.xoff;
			this.y += this.yoff;
			this.alpha -= 5;
		}

		// shimmer
		if (random(1) < 0.005) {
			let colorRed = floor(random(0, 127));
			let colorGreen = floor(random(0, 127));
			let colorBlue = floor(random(0, 127));
		} else {
			// default color
			colorRed = 175; //stars arent harsh white, tone it down a bit.
			colorGreen = 175;
			colorBlue = 175;
		}

		noStroke();
		// modification: use frameCount and cos & sin to make colors change over time
		for (let i = 0; i < 10; i++) {
			fill(
				cos(frameCount * 0.02) * colorRed + i,
				sin(frameCount * 0.02) * colorGreen + i,
				colorBlue,
				this.alpha
			);

			//draw the star
			ellipse(this.x, this.y, this.r, this.r);
		}

		// check if off screen
		if (this.x > width || this.x < -width || this.y > height || this.y < -height) {
			//if its off screen, we need to tell the main draw loop, so that it can be removed
			//from the array of stars.
			return false;
		}
	};

	// shooting star (move x and y positions of stars) function
	this.shoot = function () {
		this.shooting = true;
		this.xoff = random(-10, 10);
		this.yoff = random(-10, 10);
	};
}



////////////////////////////
// PARTICLE SYSTEM - RAINDROP CLASS
////////////////////////////
// The particle system of raindrops
// This class is similar to the previous shooting star class
// The inspiration comes from Inspiration 01 - RainyNight by Sehyeon from openprocessing
// But we didn't use the original code at all
function RaindropSystem() {

	this.raindrops = [];
	// default maximun number of raindrops (50)
	this.maxNum = RAINDROP_MAX_NUM;
	// density variables
	this.densityThreshold = 0;
	this.targetDensityThreshold = 0;
	this.basicDensity = RAINDROP_BASIC_DENSITY;
	this.densityLerprate = RAINDROP_DENSITY_LERPRATE;

	// Setup 50 raindrops
	this.setup = function () {
		for (var i = 0; i < this.maxNum; i++) {
			this.raindrops[i] = new Raindrop();
		}
	}

	// Render function (display raindrops)
	this.render = function () {
		this.densityThreshold = lerp(this.densityThreshold, this.targetDensityThreshold, this.densityLerprate);

		for (let i = this.maxNum - 1; i > -1; i--) {
			// Only when current density is lower than density threshold can display raindrops
			if (this.raindrops[i].density < this.densityThreshold) {
				this.raindrops[i].update();
				this.raindrops[i].render();
				this.raindrops[i].checkCollision();

				// remove raindrops that are off the screen
				if (this.raindrops[i].checkCollision() === false) {
					this.raindrops.splice(i, 1);
					console.log('num of deleted raindrops: ' + i);
				}
				this.maxNum = this.raindrops.length;
			}
		}
	}

	// Density function
	// durationValue receives the MQTT message
	this.setDensity = function (durationValue) {
		this.targetDensityThreshold = lerp(this.basicDensity, 1, durationValue);
	}
}

////////////////////////////
// SINGLE RAINDROP CLASS
////////////////////////////
// This class draws the raindrop and check if it hits the water
function Raindrop() {
	this.x = random(width);
	this.y = random(height);
	this.size = random(8, 10);
	// check if raindrops hits the water 
	// if true, the depth of water (or flood) will increase
	this.collided = false;

	this.density = random(1);

	// we add a wind value (adjust the x value)
	// and a speed value (adjust the y value)
	// these values receive MQTT messages to achieve user interaction
	this.update = function () {
		this.x = this.x + this.size / windOfRaindrop; // wind
		this.y = this.y + this.size / speedOfRaindrop; // speed (small value fast, large value slow)
	}
	// display raindrop
	this.render = function () {
		noStroke();
		fill(255, 150);
		ellipse(this.x, this.y, this.size, this.size);
	}
	// check if raindrops hit the water
	this.checkCollision = function () {
		// get the depth value of water 
		let oceanHeight = theOcean.getHeight(this.x);
		// the depth will increase once raindrops hit the water
		if (this.y + this.size / 2 > oceanHeight) {
			theOcean.rise();
			// console.log("oceanHeight: " + oceanHeight);
		}
		// check if raindrops are off the screen
		if (this.x >= width) {
			this.x = 0;
		}
		// check if raindrops fall into the ocean 
		if (this.y - this.size / 2 > oceanHeight) {
			// new raindrops will fall
			this.y = 0;
			console.log("this.y : " + this.y);
			// and return false to make them remove from the array
			return false;
		}
	};
}

////////////////////////////
// OCEAN CLASS
////////////////////////////
// The inspiration comes from Reference 04 - Noise Wave
// Modification of example code starts from here
function ocean() {
	// pre-defined the depth of wave (lower value is higher)
	this.depth = 4;
	this.yoff = 0;

	this.display = function () {
		noStroke();
		fill(83, 83, 252, 180);

		beginShape();

		for (let x = 0; x <= width; x += 10) {
			let y = this.getHeight(x);
			vertex(x, y);
		}
		this.yoff += 0.01;

		vertex(width, height);
		vertex(0, height);
		endShape(CLOSE);
	};

	// Increase the depth
	this.rise = function () {
		this.depth -= 0.0005; // everytime increasement (0.0001（slow),0.001(fast))
	};

	// Decrease the depth
	this.decrease = function () {
		this.depth += 0.05;
		console.log('#### this depth=' + this.depth)
	};

	// Get depth/ height
	this.getHeight = function (x) {
		let xoff = x * 0.001;
		return map(noise(xoff, this.yoff), 0, 1, 200, 230) * this.depth;
	};
}


////////////////////////////
// STAR_DEF FUNCTION
////////////////////////////
// Use array to store every single pentagram
function star_Def() {
	star[0] = new Star(0, 0, 7.5, 17.5, 5);
	star[1] = new Star(0, 0, 3.75, 8.75, 5);
	star[2] = new Star(0, 0, 3.75, 8.75, 5);
	star[3] = new Star(0, 0, 3.75, 8.75, 5);
	star[4] = new Star(0, 0, 4.6875, 10.9375, 5);
	star[5] = new Star(0, 0, 3.75, 8.75, 5);
	star[6] = new Star(0, 0, 3.75, 8.75, 5);
	star[7] = new Star(0, 0, 4.6875, 10.9375, 5);
}

////////////////////////////
// DISPLAY STAR FUNCTION
////////////////////////////
// Use push() pop() to draw and display every single pentagram
function star_Display() {
	push();
	translate(width / 3, height * 0.5);
	rotate(frameCount / -100.0);
	star[0].display();
	pop();

	push();
	translate(width * 0.6, height * 0.4);
	rotate(frameCount / -100.0);
	star[1].display();
	pop();

	push();
	translate(width * 0.4, height * 0.1);
	rotate(frameCount / -100.0);
	star[2].display();
	pop();

	push();
	translate(width * 0.1, height * 0.4);
	rotate(frameCount / -100.0);
	star[3].display();
	pop();

	push();
	translate(width * 0.9, height * 0.1);
	rotate(frameCount / -100.0);
	star[4].display();
	pop();

	push();
	translate(width * 0.9, height * 0.3);
	rotate(frameCount / -100.0);
	star[5].display();
	pop();

	push();
	translate(width * 0.7, height * 0.45);
	rotate(frameCount / -100.0);
	star[6].display();
	pop();

	push();
	translate(width * 0.2, height * 0.25);
	rotate(frameCount / -100.0);
	star[7].display();
	pop();
}


////////////////////////////
// BACKGROUND STAR(PENTAGRAM) CLASS
////////////////////////////
// Following code comes from Reference 07 from p5.js example
// Example code starts from here
class Star {
	constructor(x, y, radius1, radius2, npoints) {
		this.x = x;
		this.y = y;
		this.radius1 = radius1;
		this.radius2 = radius2;
		this.npoints = npoints;

		this.angle = TWO_PI / npoints;
		this.halfAngle = this.angle / 2.0;
	}

	display() {
		beginShape();
		noStroke();
		fill(191, 186, 163);
		for (let a = 0; a < TWO_PI; a += this.angle) {
			this.sx = this.x + cos(a) * this.radius2;
			this.sy = this.y + sin(a) * this.radius2;
			vertex(this.sx, this.sy);
			this.sx = this.x + cos(a + this.halfAngle) * this.radius1;
			this.sy = this.y + sin(a + this.halfAngle) * this.radius1;
			vertex(this.sx, this.sy);
		}
		endShape(CLOSE);
	}
}


////////////////////////////
// FOLLOWING THREE FUNCTIONS CONTROL THE BOUNCING FLOWERS 
////////////////////////////
// The following code refers to Reference 05 - JAPAN o' clock
// We added a jumpPower that allows user control via MQTT messaging 
// Modification of example code starts from here
function touchStarted() {
	touching = true;
}

// Our modification on jumpPower
function flowerJump(jumpPower) {
	touching = false;
	for (let i = 0; i < lists.length; i++) {
		lists[i].jump(jumpPower);
	}
	jumpPower = 0;
}

// Shaken value
function deviceShaken() {
	for (let i = 0; i < lists.length; i++) {
		lists[i].jump(random(3));
	}
}


////////////////////////////
// FLOWER PARTICLE SYSTEM CLASS
////////////////////////////
// The particle system of flowers refers to Reference 05 - JAPAN o' clock
// Example code starts from here
// The flower image comes from the Reference 08 - flower, by Yusuke Sasaki
class P {
	constructor() {
		// position
		this.x = random(width);
		this.y = random(height);
		this.yA = random(0.009); // velocity

		// rotation
		this.spinX = random(360);
		this.spinY = random(360);
		this.rot = random(360);
		this.setV(1);

		// size
		this.size = size / 50 + random(size / 60);
	}

	// set the velocity
	setV(s) {
		// 
		this.xV = (random(1) - 0.5) * s / 2;
		this.yV = (random(1) * -1 - 0.1) * s;
		// set rotation
		this.spinXV = random(2) + 1;
		this.spinYV = random(2) + 1;
		this.rotV = random(1) + 0.5;
	}

	jump(s) {
		this.y -= random(5) + 0.5;
		this.setV(s);
	}

	// display flowers
	act() {
		this.spinX += this.spinXV + abs(this.yV);
		this.spinY += this.spinYV + abs(this.yV);
		this.rot += this.rotV + abs(this.yV) * 2;
		this.x += this.xV;
		this.yV += this.yA;
		this.y += this.yV;

		// load flower image to display
		push();
		translate(this.x, this.y);
		scale(sin(radians(this.spinX)), sin(radians(this.spinY)));
		rotate(radians(this.rot));
		image(flowerImg, 0, 0, this.size * 2, this.size * 2);
		pop();

		// check edges
		if (this.x >= width || this.x <= 0) {
			this.xV *= -1;
		}

		if (this.y <= 0) {
			this.yV *= -0.5;
			this.y += 1;
		}

		// stop bouncing when flowers are on the ground
		if (this.y >= height) {
			this.xV = 0;
			this.y = height;
			this.yV = 0;
			this.rotV = 0;
			this.spinXV = 0;
			this.spinYV = 0;
		}
	}

}

////////////////////////////
// BIRDS CLASS
////////////////////////////
// The inspiration comes from Reference 06 - Interactive Environment Project, by Joseph Penders
// Original example use curveVertex to draw the bird and mouseX and mouseY to control its movement
// We created a Class for birds, and added a move function 
class Birds {
	constructor() {
		this.x = random(width / 1.5, width - width / 6);
		this.y = random(height / 10, height / 3);
		this.vx = random(1, 1.1);
		this.vy = random(-0.1, 0.2);
	}

	move() {
		this.x = this.x - this.vx;
		if (this.x < -width / 5 || this.x > width * 1.2) {
			this.vx *= -1;
		}
		this.y -= this.vy;
		if (this.y > height / 3 || this.y < -height / 10) {
			this.vy *= -1;
		}
	}
	// Modification of example code starts from here
	display() {
		beginShape();
		noStroke();
		fill(180, 180, 180);
		curveVertex(this.x, this.y);
		curveVertex(this.x, this.y);
		curveVertex(this.x + 19, this.y - 13);
		curveVertex(this.x + 32, this.y + 1);
		curveVertex(this.x + 18, this.y - 7);
		endShape(CLOSE);
		beginShape();
		noStroke();
		fill(180, 180, 180);
		curveVertex(this.x + 28, this.y + 1);
		curveVertex(this.x + 28, this.y + 1);
		curveVertex(this.x + 44, this.y - 14);
		curveVertex(this.x + 59, this.y - 1);
		curveVertex(this.x + 45, this.y - 7);
		endShape(CLOSE);
	}
}


////////////////////////////
// MQTT MESSAGE HANDLING
////////////////////////////
function setupMqtt() {
	socket = io.connect(HOST);
	socket.on('mqttMessage', receiveMqtt);
}


function receiveMqtt(data) {
	var topic = data[0];
	var message = data[1];
	console.log('Topic: ' + topic + ', message: ' + message);

	// when the topic includes our MQTT subscription name
	if (topic.includes('Group03_LightTheCity')) {
		// when rain label is received 
		if (message.includes('rain_Label')) {

			console.log("message: " + message);
			let myRainLabel = message.split(',')[1];
			console.log("myRainLabel, " + myRainLabel);
			// display rain mode
			if (myRainLabel == 'Rain') {
				rainMode_Received = true;
				fogMode_Received = false;
				flowerMode_Received = false;
				starMode_Received = false;
				// play the sound effect for rain
				switchSound(1);

			}
		}

		// when flower label is received 
		if (message.includes('flower_Label')) {
			console.log("message: " + message);
			let myFlowerLabel = message.split(',')[1];
			console.log("myFlowerLabel: " + myFlowerLabel);
			// display flower mode
			if (myFlowerLabel == "Flower") {
				rainMode_Received = false;
				fogMode_Received = false;
				flowerMode_Received = true;
				starMode_Received = false;
				// play the sound effect for flower
				switchSound(2);

			}
		}

		// when fog label is received 
		if (message.includes('fog_Label')) {
			console.log("message: " + message);
			let myFogLabel = message.split(',')[1];
			console.log("myFogLabel: " + myFogLabel);
			// display fog mode
			if (myFogLabel == "Fog") {
				rainMode_Received = false;
				fogMode_Received = true;
				flowerMode_Received = false;
				starMode_Received = false;
				// play the sound effect for fog
				switchSound(0);
			}
		}

		// when star label is received 
		if (message.includes('star_Label')) {
			console.log("message: " + message);
			let myStarLabel = message.split(',')[1];
			console.log("myStarLabel: " + myStarLabel);
			// display star mode
			if (myStarLabel == "Star") {
				rainMode_Received = false;
				fogMode_Received = false;
				flowerMode_Received = false;
				starMode_Received = true;
				// play the sound effect for star
				switchSound(3);
			}
		}


		if (message.includes('gesture_Duration')) {
			let receivedDurationValue = message.split(',')[1];

			// map the gesture duration value
			if (receivedDurationValue <= 1000) {
				userInputRaindropDensity = map(receivedDurationValue, 0, 1000, 0, 1);
				windOfRaindrop = map(receivedDurationValue, 0, 1000, 10, 2);
				userInputFog = map(receivedDurationValue, 0, 1000, 0.5, 4);
				speedOfRaindrop = map(receivedDurationValue, 0, 1000, 3, 2);
				jumpPowerOfFlowers = map(receivedDurationValue, 0, 1000, 3, 10);

				// console.log("userInputFog: " + userInputFog);
				// console.log("windOfRaindrop: " + windOfRaindrop);
				// console.log("userInputRaindropDensity: " + userInputRaindropDensity);
				// console.log("receivedDurationValue: " + receivedDurationValue);
				// console.log("speedOfRaindrop: " + speedOfRaindrop);
				if (flowerMode_Received) {
					flowerJump(jumpPowerOfFlowers)
					console.log("speedOfRaindrop: " + jumpPowerOfFlowers);
				}


			} else {
				userInputRaindropDensity = 1;
				windOfRaindrop = 2;
				userInputFog = 4;
				speedOfRaindrop = 1;
				jumpPowerOfFlowers = 10;

				console.log("userInputFog: " + userInputFog);
				console.log("windOfRaindrop: " + windOfRaindrop);
				console.log("userInputRaindropDensity: " + userInputRaindropDensity);
				console.log("receivedDurationValue: " + receivedDurationValue);
				console.log("speedOfRaindrop: " + speedOfRaindrop);
				if (flowerMode_Received) {
					flowerJump(speedOfRaindrop);
					console.log("speedOfRaindrop: " + jumpPowerOfFlowers);
				}
			}

			// when star and flower labels are received
			// gradually decrease the depth of the ocean
			if (starMode_Received || flowerMode_Received) {
				if (theOcean.depth < 4) {
					theOcean.decrease();
				}
			}

			// when the star mode is received 
			// shoot the star
			// the number of shooting stars is determined by gesture duration value
			if (starMode_Received) {
				let shootNum = map(receivedDurationValue, 0, 1500, 0, 80);
				for (let i = 0; i < shootNum; i++) {
					let idx = round(random(199));
					console.log(idx)
					console.log(shootingStars[idx])
					shootingStars[idx].shoot();
				}
			}

		}
	}
}

