namespace ca.mcgill.ecse223.block.model;
use Block223Persistence.ump;

class Block223 {
   1 <@>- * User users;
   1 <@>- * UserRole roles;
   1 <@>- * Game games;

   //Anne-Julie
   public Game findGame(String name){
   List<Game> games = this.getGames();
   for(Game game : games){
   String gameName = game.getName();
   if(name == gameName){
   return game;
   }
   }
   return null;
   }
   //end

}

class User {
   unique username;
   1 -> 1..2 UserRole roles;

   //Mairead
   public static UserRole findPassword(String password, User user){
    List<UserRole> roles = user.getRoles();
	for(UserRole role : roles) {
    String rolePassword = role.getPassword();
    if(password == rolePassword){
    	return role;
    	}

   }
	return null;

  }
  //end

}

class UserRole {

   abstract;
   password;
}

class Admin {
   isA UserRole;
}

class Player {
   isA UserRole;
}

class Game {
   const Integer MIN_NR_LEVELS = 1;
   const Integer MAX_NR_LEVELS = 99; // this is somewhat redundant because the max multiplicity is enforced by Umple
   const Integer PLAY_AREA_SIDE = 390; // play area is now constant
   const Integer WALL_PADDING = 10;
   const Integer COLUMNS_PADDING = 5;
   const Integer ROW_PADDING = 2;
   unique name;
   Integer nrBlocksPerLevel;
   * -- 1 Admin admin;
   1 <@>- * Block blocks;
   1 <@>- 1..99 Level levels;
   1 <@>- * BlockAssignment blockAssignments;
   1 <@>- 1 Ball ball;
   1 <@>- 1 Paddle paddle;

   //George
   public Block findBlock(int id){
   List<Block> blocks = this.getBlocks();
   for(Block block : blocks){
   int blockId = block.getId();
   if(id == blockId){
   return block;
   }
   }
   return null;
   }
   //Yannick

      before constructor, setNrBlocksPerLevel{
         if(aNrBlocksPerLevel <= 0){
            throw new RuntimeException("The  number  of  blocks  per  level  must be greater than zero");
         }
      }

      after setName{
      		if(!setName(aName)){
      			throw new RuntimeException("The name of a game must be unique");
      		}
      }

      //Anne-Julie

      before setName{
         if(aName.equals("The name of a game must be specified.")){
            throw new RuntimeException("");
         }
      }
   //end

}

class Block {
   const Integer MIN_COLOR = 0;
   const Integer MAX_COLOR = 255;
   const Integer MIN_POINTS = 1;
   const Integer MAX_POINTS = 1000;
   const Integer SIZE = 20;
   autounique id;
   Integer red;
   Integer green;
   Integer blue;
   Integer points;

    //George

   before constructor, setRed{
      if(aRed <MIN_COLOR || aRed > MAX_COLOR){
         throw new RuntimeException ("Red must be between 0 and 255.");
      }
   }
	before constructor, setGreen{
   if(aGreen <MIN_COLOR || aGreen > MAX_COLOR){
   throw new RuntimeException ("Green must be between 0 and 255.");
   }
}
	before constructor, setBlue{
   if(aBlue <MIN_COLOR || aBlue > MAX_COLOR){
   throw new RuntimeException ("Blue must be between 0 and 255.");
   }
}
	before constructor, setPoints{
   if(aPoints <MIN_POINTS || aPoints > MAX_POINTS){
   throw new RuntimeException ("Points must be between 1 and 10000.");
   }
}
//end


}

// random attribute not needed anymore
// Each level is filled up with random blocks just before playing the level to reach the nrBlocksPerLevel defined in Game
class Level {

//Mert

public BlockAssignment findBlockAssignment(int aGridHorizontalPosition, int aGridVerticalPosition) {
		BlockAssignment foundAssignment = null;
		for(BlockAssignment position: getBlockAssignments()) {
			if(position.getGridHorizontalPosition() == aGridHorizontalPosition && position.getGridVerticalPosition() == aGridVerticalPosition) {
				foundAssignment = position;
			}
		}
		return foundAssignment;
	  }
	  //end

}

class BlockAssignment {
   Integer gridHorizontalPosition;
   Integer gridVerticalPosition;
   * -- 1 Level level;
   * -- 1 Block block;

   //George

   before constructor, setGridHorizontalPosition{
   int maxNumberHorizontalBlocks = (390 - 2 * 5) / Block.SIZE;
   if (aGridHorizontalPosition <= 0 || aGridHorizontalPosition > maxNumberHorizontalBlocks){
   throw new RuntimeException("The horizontal position must be between 1 and " + maxNumberHorizontalBlocks +".");
   }
}
 before constructor, setGridVerticalPosition{
   int maxNumberVerticalBlocks = (390 - 2 * 3) / Block.SIZE;
   if (aGridVerticalPosition <= 0 || aGridVerticalPosition > maxNumberVerticalBlocks){
   throw new RuntimeException("The vertical position must be between 1 and " + maxNumberVerticalBlocks +".");
   }
}
}

class Ball {
   const Integer BALL_DIAMETER = 10;
   Integer minBallSpeedX;
   Integer minBallSpeedY;
   Double ballSpeedIncreaseFactor;

   //Yannick
   before constructor, setMinBallSpeedX{
      if(aMinBallSpeedX <= 0){
         throw new RuntimeException ("The  minimum  speed  of  the  ball  must be greater than zero.");
      }
   }

   before constructor, setMinBallSpeedY{
      if(aMinBallSpeedY <= 0){
         throw new RuntimeException ("The  minimum  speed  of  the  ball  must be greater than zero.");
      }
   }

   before constructor, setBallSpeedIncreaseFactor{
      if(aBallSpeedIncreaseFactor <= 0){
         throw new RuntimeException ("The speed increase factor of the ball must be greater than zero.");
      }
   }
}

class Paddle {
   const Integer PADDLE_WIDTH = 5;
   const Integer VERTICAL_DISTANCE = 30;
   Integer maxPaddleLength;
   Integer minPaddleLength;
}
