<repo_name>Pierrik/GuitarZero<file_sep>/src/SelectMode.java
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;

import java.lang.*;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.*;

import javax.swing.JFrame;
import javax.swing.JLabel;

/**
 * Select Mode.
 *
 * @author <NAME>
 * @version 2.0, March 2019.
 */
public class SelectMode extends JPanel {


  /**
   * Initialises the GUI classes for a carousel with menu options specific to Select Mode
   */
  public SelectMode() throws NoSongsException  {

    ArrayList<JLabel> menuOptions = new ArrayList<>();

    String cd = System.getProperty("user.dir");
    String bundleDirPath = "../local_store/bundle_files/";

    File[] song_folders = new File(bundleDirPath).listFiles();

    if (song_folders == null || song_folders.length == 0){
      System.out.println("No songs in local store.");
      throw new NoSongsException("No songs in local store");
    }

    for (File song_folder : song_folders) {

      File albumCover = new File("");
      String songName;

      if (!song_folder.getName().equals(".DS_Store")) {

        songName = song_folder.getName();

        File[] song_files = song_folder.listFiles();

        for (File song_file : song_files) {

          if (getExtension(song_file.getName()).equalsIgnoreCase("png")) {
            albumCover = song_file;
          }


        }

        JLabel label = new JLabel(new ImageIcon(albumCover.getPath()));
        label.setText(songName);

        menuOptions.add(label);
      }
    }

    // Initialise the model, controller, view GUI classes
    CarouselView       view       = new CarouselView( menuOptions);
    CarouselModel      model      = new CarouselModel( view );
    CarouselController controller = new CarouselController( model , Mode.SELECT);
    try {
      Thread.sleep(200);
    } catch (InterruptedException e){
      e.printStackTrace();
    }
    Thread controllerThread = new Thread(controller);
    controllerThread.start();
    this.add(view);
  }

  /**
   * Gets the extension of a file
   * @param fileName the name of the file to check
   * @return the file extension
   */
  private String getExtension (String fileName) {

    String extension = "";

    int i = fileName.lastIndexOf('.');

    if (i > 0) {
      extension = fileName.substring(i + 1);
    }

    return extension;
  }

  /**
   * Draws the highway background that the carousel will be placed on top of
   * @param g
   */
  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g); // paint the background image and scale it to fill the entire space

    Image highway = null;
    try {
      highway = ImageIO.read(new File("../assets/Done/Highway.bmp"));
    } catch (IOException e) {
      e.printStackTrace();
    }
    g.drawImage(highway, -7, 5, this);
  }

}<file_sep>/src/TutorialModeModel.java
/**
 * CarouselModel
 *
 * @author  <NAME>
 * @version 1.00, March 2019.
 */

public class TutorialModeModel {
  TutorialModeView view;

  public TutorialModeModel (TutorialModeView view) {
    this.view = view;
  }

  /**
   * Calls the rightMovement method in the tutorialView file causing icons to shift right
   */
  public void right() {
    view.rightMovement();
  }

  /**
   * Calls the leftMovement method in the tutorialView file causing icons to shift left
   */
  public void left() {
    view.leftMovement();
  }

}
<file_sep>/src/NoPictureException.java
/**
 * NoPictureException.
 * Can be thrown when no pictures are found in the local store directory.
 *
 * @author <NAME>
 * @version 1.0, March 2019
 */
public class NoPictureException extends Exception {
  public NoPictureException(String message){
    super(message);
  }
}<file_sep>/src/ModeChanger.java
/**
 * Mode Changer.
 *
 * @author <NAME>
 * @version 1.0, March 2019
 */
public class ModeChanger implements Runnable{
  private Mode mode;

  public ModeChanger(Mode mode){
    this.mode = mode;
  }

  public void run() {
    Run.changeMode(mode);
  }
}
<file_sep>/server/MockClient.java
import java.io.*;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * MockClient.
 *
 * @author  <NAME>
 * @version 2.09, February 2019.
 */
public class MockClient {
  private String host;
  private int    port;

  private final static int BUFFER_SIZE = 4092;

  MockClient(String host, int port){
    this.host = host;
    this.port = port;
  }

  /**
   * Uploads the given bundle to the server.
   *
   * @param fileName: The filepath of the file to upload.
   * @param method: Upload method (UPLOAD_BUNDLE or UPLOAD_PREVIEW).
   */
  public void uploadFile(String fileName, String method){
    try {
      Socket sck = new Socket(this.host, this.port);

      // Instantiating byte array of correct size to store file
      File file = new File(fileName);
      byte[] bytes = new byte[(int) file.length()];

      // Streams for reading/writing the file
      DataInputStream dataIn = new DataInputStream(new FileInputStream(file));
      DataOutputStream dataOut = new DataOutputStream(sck.getOutputStream());

      // Reading the file into the byte array
      dataIn.readFully(bytes, 0, bytes.length);

      // Writing the file to the socket output stream (from the byte array)
      dataOut.writeUTF(method + "/" + fileName);
      dataOut.writeLong(file.length());
      dataOut.write(bytes, 0, bytes.length);
      dataOut.flush();

      // Cleaning up
      sck.close();

    } catch ( Exception exn ) {
      System.out.println( exn ); System.exit( 1 );
    }
  }

  /**
   * Downloads the given file from the server, and unzips it in the corresponding directory.
   *
   * @param fileName: The filepath of the file to download.
   * @param method: Download method (DOWNLOAD_BUNDLE or DOWNLOAD_PREVIEW).
   */
  public void downloadFile(String fileName, String method){
    try {
      // Checking if local_store directory exists, and creates it if it doesn't yet
      String bundleDir = "../local_store/bundle_files/";
      String previewDir = "../local_store/preview_files/";

      if (Files.notExists(Paths.get(bundleDir))) {
        Files.createDirectories(Paths.get(bundleDir));
      }
      if (Files.notExists(Paths.get(previewDir))) {
        Files.createDirectories(Paths.get(previewDir));
      }

      // Requesting to download the file
      Socket sck = new Socket(this.host, this.port);
      DataOutputStream dataOut = new DataOutputStream(sck.getOutputStream());
      dataOut.writeUTF(method + "/" + fileName);
      dataOut.flush();

      // Attempting to receive the file
      DataInputStream dataIn = new DataInputStream(sck.getInputStream());
      BufferedOutputStream fileOut;
      String zipPath;

      if (method.equals("DOWNLOAD_BUNDLE")) {
        zipPath = bundleDir + fileName;
      }
      else if (method.equals("DOWNLOAD_PREVIEW")) {
        zipPath = previewDir + fileName;
      }
      else {
        sck.close();
        return;
      }

      File file = new File(zipPath);
      fileOut = new BufferedOutputStream(new FileOutputStream(file));

      int fileSize = (int)dataIn.readLong();
      int n;
      byte[] buf = new byte[BUFFER_SIZE];
      while (fileSize > 0
          && (n = dataIn.read(buf, 0, (int) Math.min(buf.length, fileSize))) != -1) {
        fileOut.write(buf, 0, n);
        fileSize -= 1;
      }

      // Cleaning up
      fileOut.close();
      sck.close();

      unzip(zipPath, "../local_store/bundle_files/");

    } catch ( Exception exn ) {
      System.out.println( exn ); System.exit( 1 );
    }

  }

  /**
   * Deletes specified file.
   *
   * @param filePath: File path of file to delete.
   */
  public static void deleteFile(String filePath){
    try {
      Path path = Paths.get(filePath);
      Files.delete(path);
    } catch (IOException e){
      e.printStackTrace();
    }
  }

  /**
   * Removes the parentheses and file extension from a bundle file name.
   * e.g. "Song(bundle).zip" to "Song".
   *
   * @param bundle: Bundle file name.
   * @return: Song name.
   */
  public static String getSongBundle(String bundle){
    return bundle.substring(0, bundle.length() - 12);
  }

  /**
   * Removes the parentheses and file extension from a preview file name.
   * e.g. "Song(preview).zip" to "Song".
   *
   * @param preview: Preview file name.
   * @return: Song name.
   */
  public static String getSongPreview(String preview){
    return preview.substring(0, preview.length() - 13);
  }

  /**
   * Unzips the contents of a specified .zip file to a specified destination directory, and
   * deletes the original .zip file afterwards.
   *
   * @param zipFilePath: File path to zip file.
   * @param destDir: Destination directory.
   */
  public static void unzip(String zipFilePath, String destDir) {
    // Create output directory if it doesn't exist
    File dir = new File(destDir);
    if(!dir.exists()) {
      dir.mkdirs();
    }

    try {
      // Unzipping and writing each entry to disk
      ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
      ZipEntry entry = zipIn.getNextEntry();

      while (entry != null) {
        String filePath = destDir + "/" + entry.getName();
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        byte[] buf = new byte[BUFFER_SIZE];
        int read = 0;
        while ((read = zipIn.read(buf)) != -1) {
          bos.write(buf, 0, read);
        }
        bos.close();
        zipIn.closeEntry();
        entry = zipIn.getNextEntry();
      }
      zipIn.closeEntry();
      zipIn.close();

      // Deleting the remaining zip file
      deleteFile(zipFilePath);

    }
    catch (EOFException e){
      // JVM bug (JVM-6519463) - So catch every time and do nothing with it (extraction still works)
    }
    catch (Exception e) {
      e.printStackTrace();
    }

  }

  /**
   * Requests a directory listing of the previews directory on the server.
   *
   * @return ArrayList: ArrayList of filenames in previews directory (songs available to buy).
   */
  public ArrayList<String> listDirectory(){
    try{
      // Requesting the directory listing
      Socket sck = new Socket(this.host, this.port);
      DataOutputStream out = new DataOutputStream(sck.getOutputStream());
      out.writeUTF("LIST_DIRECTORY");
      out.flush();

      // Attempting to receive the filenames and build arraylist
      DataInputStream  dataIn  = new DataInputStream(sck.getInputStream());
      ArrayList<String> songNames = new ArrayList<>();

      String songName;
      while (!(songName = dataIn.readUTF()).equals("END")){
        songNames.add(songName);
      }

      // Cleaning up and returning arraylist of filenames
      sck.close();
      return songNames;

    } catch ( Exception exn ) {
      System.out.println(exn); return null;
    }
  }

}<file_sep>/src/StoreMode.java
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * StoreMode.
 * @author <NAME>
 * @author <NAME> (exception handling)
 * @version 2.13, March 2019
 */
public class StoreMode extends JPanel {

  // Server settings
  private static final String HOST       = "localhost";
  private static final int    PORT       = 8888;
  private final static int    MODE_DELAY = 150;
  private static final int    POINT_0_0  = 0;

  // Store settings
  private static final String PREVIEWS = "../local_store/preview_files/";

  public StoreMode() {
    String songName = null;
    String previewDir = null;
    MockClient client = null;
    try {
      client = new MockClient(HOST, PORT);
    }
    catch(Exception e){
      System.out.println("Enable to create MockClient. /STOREMODE");
      GameUtils.changeModeOnNewThread(Mode.SLASH);
    }

    // Getting preview filenames of all available songs on the server
    ArrayList<String> fileNames = client.listDirectory();

    // Downloading and unzipping all previews, and giving each title/cover a JLabel
    ArrayList<JLabel> menuOptions = new ArrayList<>();
    for (String fileName : fileNames){
      try {
        // Downloading and unzipping preview (and deleting zip after)
        client.downloadFile(fileName, "DOWNLOAD_PREVIEW");
        songName = MockClient.getSongPreview(fileName);
        previewDir = PREVIEWS + songName + "/";
        MockClient.unzip(PREVIEWS + fileName, previewDir);
      }
      catch(Exception e){
        System.out.println("Couldn't download files. /STOREMODE");
        GameUtils.changeModeOnNewThread(Mode.SLASH);
      }
      // Reading in the cover image and song name, assigning to a JLabel and adding to ArrayList
      File[] previewContents = new File(previewDir).listFiles();
      try {
        for (File cover : previewContents) {
          JLabel label = new JLabel(new ImageIcon(previewDir + cover.getName()));
          label.setText(songName);
          menuOptions.add(label);
        }
      }
      catch(Exception e){
        System.out.println("Can't create JLabels in Carousel. /STOREMODE");
        GameUtils.changeModeOnNewThread(Mode.SLASH);
      }
    }
    CarouselController controller = null;
    CarouselView view = null;
    try {
      // Initialise the model, controller, view GUI classes
      view = new CarouselView(menuOptions);
      view.displayCurrency();
      CarouselModel model = new CarouselModel(view);
      controller = new CarouselController(model, Mode.STORE);
    }
    catch(Exception e){
      System.out.println("Unable to start MVC. /STOREMODE");
      GameUtils.changeModeOnNewThread(Mode.SLASH);
    }
    try {
      Thread controllerThread = new Thread(controller);
      controllerThread.start();
    }
    catch(Exception e){
      System.out.println("Enable to start Thread for controller. /STOREMODE");
      GameUtils.changeModeOnNewThread(Mode.SLASH);
    }
    this.add(view);
    //view.setVisible(true);

  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g); // paint the background image and scale it to fill the entire space

    Image highway = null;
    try {
      highway = ImageIO.read(new File("../assets/Done/Highway.bmp"));
    } catch (IOException e) {
      System.out.println("Unable to load highway");
      GameUtils.changeModeOnNewThread(Mode.SLASH);
    }
    g.drawImage(highway, -7, 5, this);
  }

  public void sleep(int millis){
    try {
      Thread.sleep(millis);
    } catch (InterruptedException e) {
      System.out.println("Woken from sleep");
      GameUtils.changeModeOnNewThread(Mode.SLASH);
    }
  }

}<file_sep>/src/NoSongsException.java
/**
 * NoSongsException.
 * Can be thrown when no songs are found in the local store directory.
 *
 * @author <NAME>
 * @version 1.0, March 2019
 */
public class NoSongsException extends Exception {
  public NoSongsException(String message){
    super(message);
  }
}<file_sep>/src/StoreManagerButton.java
public enum StoreManagerButton {
  TITLE, COVER, SONG, SAVE;
}
<file_sep>/src/CarouselModel.java
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.swing.*;

/**
 * CarouselModel
 *
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @version 2.00, March 2019.
 */

public class CarouselModel {
  CarouselView view;
  File currencyFile;
  private static int  totalCurrency;
  final static String BUNDLES       = "../local_store/bundle_files/";
  final static String HOST          = "localhost";
  final static int    PORT          = 8888;
  final static int    POP_UP_TIME   = 3000;
  final static int    POP_UP_WIDTH  = 260;
  final static int    POP_UP_HEIGHT = 160;
  final static int    POP_UP_Y      = 50;
  final static int    POP_UP_X      = 275;
  JLabel popUp;

  /**
   * Skeleton constructor for later use
   */
  public CarouselModel(CarouselView view) {
    this.view = view;

    // If the currency file can't be loaded, do not start the game
    try {
      this.currencyFile = Currency.findCurrencyFile();
    } catch (Exception e) {
      e.printStackTrace();
    }

    // If currency file cannot be read properly, do not start the game
    try {
      this.totalCurrency = Currency.loadCurrencyFile(this.currencyFile);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Calls the rightMovement method in the carouselView file causing icons to shift right
   */
  public void right() {
    view.rightMovement();
  }

  /**
   * Calls the leftMovement method in the carouselView file causing icons to shift left
   */
  public void left() {
    view.leftMovement();
  }


  /**
   * Returns a string from the chosenOption method in the carouselView file allowing a user to
   * choose a menu option
   */
  public String select() {

    //System.out.println(view.chosenOption());
    return view.chosenOption();
  }

  /**
   * Downloads a song to local directory.
   */
  public void buySong(String songName) {

    String bundleName = songName + "(bundle).zip";

    if (totalCurrency > 0 && !isInLocalDir(songName)) {
      try {
        updateCurrencyAndLocalStore(bundleName, songName);
      } catch (Exception e) {
        e.printStackTrace();
      }
    } else if (totalCurrency < 1 && isInLocalDir(songName)){
      popUp("../assets/NoMoneyAndSongOwnedPopUp.jpg", POP_UP_TIME);
    } else if (totalCurrency > 0 && isInLocalDir(songName)){
      popUp("../assets/SongOwnedPopUp.jpg", POP_UP_TIME);
    } else {
      popUp("../assets/NoMoneyPopUp.jpg", POP_UP_TIME);
    }
  }

  /**
   * Updates currency and local store.
   */
  public void updateCurrencyAndLocalStore(String bundleName, String songName) throws Exception {
    totalCurrency --;
    Currency.saveCurrencyFile(totalCurrency);

    MockClient client = new MockClient(HOST, PORT);
    client.downloadFile(bundleName, "DOWNLOAD_BUNDLE");
    String bundlesDir = BUNDLES + songName + "/";
    MockClient.unzip(BUNDLES + bundleName, bundlesDir);
  }

  /**
   * Displays pop up messages.
   */
  public void popUp(String pngPath, int time) {
    popUp = new JLabel(new ImageIcon(pngPath));
    popUp.setSize(POP_UP_WIDTH, POP_UP_HEIGHT);
    popUp.setBounds(POP_UP_X, POP_UP_Y, POP_UP_WIDTH, POP_UP_HEIGHT);
    this.view.add(popUp, 0);
    this.view.repaint();
    try {
      Thread.sleep(time);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    this.view.remove(popUp);
  }

  /**
   * Checks if the song is already in the local directory.
   */
  public static boolean isInLocalDir(String song) {
    // checking if local_store directory exists
    String bundleDir = "../local_store/bundle_files/";

    if (Files.notExists(Paths.get(bundleDir))) {
      return false;
    } else {
      File tmpDir = new File("../local_store/bundle_files/" + song);
      if (tmpDir.exists())
        return true;
      else
        return false;
    }
  }

}
<file_sep>/README.md
# GuitarZero

Instructions:


Server:
Put Server.java, Handler.java and InvalidSongException.java in one directory.

cd to this directory and enter the following commands -
  javac Server.java
  java Server



Store Manager Mode:
Put StoreManagerMain.java, StoreManagerController.java, StoreManagerModel.java, StoreManagerView.java, StoreManagerButton.java

cd to this directory and enter the following commands -
  javac StoreManagerMain.java
  java StoreManagerMain



GuitarZero:
Have ALL source files in one directory. Ensure the local_store directory is set up properly if intend on using Select mode, and ensure the
server is running if you intend on buying songs in Store mode. local_store/bundle_files/ is where bundles are stored, and 
local_store/preview_files is where the store mode caching is stored.

cd to this directory and enter the following commands -

(Windows)
  set CLASSPATH=jinput-2.0.9.jar;.
  javac *.java
  java Run
  
(Linux)
  $ CLASSPATH=jinput-2.0.9.jar:.
  $ export CLASSPATH
  $ javac *.java
  $ java Run
<file_sep>/src/Mode.java
public enum Mode {
  SLASH, SELECT, STORE, PLAY, TUTORIAL, EXIT;
}
<file_sep>/src/PlayModeView.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Image;
import java.io.IOException;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import java.util.ArrayList;

/**
 * PlayModeView
 *
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @version 5.1, March 2019.
*/
public class PlayModeView extends JPanel{

  ArrayList<Note> notes = new ArrayList<Note>();
  private static int frame;

  // Setup background animation values
  private static int backgroundFrameCount = 1;
  private static int backgroundFrameDelay = 100;

  // Create BufferedImage array to store the background frames
  static BufferedImage[] bg = new BufferedImage[backgroundFrameCount];

  // Initialise JLabels to display notes and game values
  private JLabel coverArtLabel;
  private JLabel multiplierLabel;
  private JLabel currencyLabel;
  private JLabel scoreLabel;
  private JLabel streakLabel;
  private JLabel zeroPowerLabel;
  private JLabel noteLabel;
  private JLabel noteCollected;
  private JLabel endStatisticsBackground;
  private JLabel endStatisticsImg;
  private JLabel endStatisticsTitle;
  private JLabel endStatisticsScore;
  private JLabel endStatisticsCurrency;
  private JLabel endStatisticsNote;
  private JLabel[] activeNotes = new JLabel[6];
  private JLabel[] collectedNotes = new JLabel[6];

  // Path to the background of the game
  private static final String HIGHWAY_PATH = "../assets/Done/Highway.bmp";

  // Dimensions for displaying the end statistics
  private static final int END_STATISTICS_WIDTH = 400;
  private static final int END_STATISTICS_HEIGHT = 400;
  private static final int END_STATISTICS_X = 300;
  private static final int END_STATISTICS_Y = 100;
  private static final int END_STATISTIC_MARGIN = 20;
  private static final int END_STATISTIC_TEXT_HEIGHT = 40;
  // Dimensions for displaying the cover art
  private static final int COVER_ART_WIDTH = 200;
  private static final int COVER_ART_HEIGHT = 200;
  private static final int COVER_ART_X = 50;
  private static final int COVER_ART_Y = 28;

  // Dimensions for displaying the score multiplier
  private static final int MULTIPLIER_WIDTH = 100;
  private static final int MULTIPLIER_HEIGHT = 100;
  private static final int MULTIPLIER_X = 50;
  private static final int MULTIPLIER_Y = 250;

  // Dimensions for displaying the currency earned during the game
  private static final int CURRENCY_WIDTH = 140;
  private static final int CURRENCY_HEIGHT = 30;
  private static final int CURRENCY_X = 200;
  private static final int CURRENCY_Y = 437;

  // Dimensions for displaying the zero power icon during zero power mode
  private static final int ZERO_POWER_WIDTH = 174;
  private static final int ZERO_POWER_HEIGHT = 192;
  private static final int ZERO_POWER_X = 726;
  private static final int ZERO_POWER_Y = 140;

  // Dimensions for displaying the current score during the game
  private static final int SCORE_X = 50;
  private static final int SCORE_Y = 400;
  private static final int SCORE_WIDTH = 200;
  private static final int SCORE_HEIGHT = 100;

  // Size of the text for the score label and the streak label
  private static final int TEXT_SIZE = 32;

  // Dimensions for displaying the current note streak
  private static final int STREAK_WIDTH = 200;
  private static final int STREAK_HEIGHT = 200;
  private static final int STREAK_X = 440;
  private static final int STREAK_Y = 28;

  // Dimensions and asset paths for displaying the notes on the fretboard at the bottom of the highway
  private static final int FRETBOARD_Y = 395;
  private static final String FRETBOARD_WHITE = "../assets/Done/WhiteNoteToPlay.png";
  private static final String FRETBOARD_BLACK = "../assets/Done/BlackNoteToPlay.png";
  private static final String FRETBOARD_WHITE_COLLECTED = "../assets/Done/WhiteNoteCollected.png";
  private static final String FRETBOARD_BLACK_COLLECTED = "../assets/Done/BlackNoteCollected.png";
  private static final int FRETBOARD_NOTE_WIDTH = 100;
  private static final int FRETBOARD_NOTE_HEIGHT = 100;
  private static final int FRETBOARD_LEFT_X = 350;
  private static final int FRETBOARD_MIDDLE_X = 450;
  private static final int FRETBOARD_RIGHT_X = 550;

  // Amount of note buttons on the guitar
  private static final int TOTAL_NOTE_BUTTONS = 6;

  // The y coordinate that causes a note to be removed from the screen if it falls past this point
  private static final int DROP_NOTE_BOUND = 463;

  public PlayModeView(){
    frame = 0;
    try{
      for(int i = 0; i<backgroundFrameCount; i++){
        bg[i] = ImageIO.read(new File(HIGHWAY_PATH));
      }
    }
    catch(Exception e){
      e.printStackTrace();
    }
    this.setLayout(null);
  }

  /**
   * displayEndValues
   * @param img The cover art of the current song
   * @param songTitle The current songs name
   * @param score The final score of the game
   * @param currency The users currency total
   */
  public void displayEndValues(File img, String songTitle, String score, String currency){
    String[] segments = songTitle.split("/");
    String idStr = segments[segments.length-1];
    songTitle = idStr;
    endStatisticsBackground = new JLabel(new ImageIcon("../assets/emptyBox.jpeg"));
    endStatisticsBackground.setBounds(END_STATISTICS_X,END_STATISTICS_Y,END_STATISTICS_WIDTH,END_STATISTICS_HEIGHT);

    //SONG NAME
    endStatisticsTitle = new JLabel("Song: "+songTitle);
    endStatisticsTitle.setBounds(END_STATISTICS_X + (END_STATISTICS_WIDTH/2) - (COVER_ART_WIDTH/2), END_STATISTICS_Y+COVER_ART_HEIGHT+(2*END_STATISTIC_MARGIN), COVER_ART_WIDTH, END_STATISTIC_TEXT_HEIGHT);
    endStatisticsTitle.setForeground(Color.BLACK);
    scoreLabel.setFont(new Font("Serif", Font.BOLD, TEXT_SIZE));
    endStatisticsTitle.setVisible(true);
    add(endStatisticsTitle);

    //GAME SCORE
    endStatisticsScore = new JLabel("Score: "+score);
    endStatisticsScore.setBounds(END_STATISTICS_X + (END_STATISTICS_WIDTH/2) - (COVER_ART_WIDTH/2), END_STATISTICS_Y+COVER_ART_HEIGHT+(3*END_STATISTIC_MARGIN), COVER_ART_WIDTH, END_STATISTIC_TEXT_HEIGHT);
    endStatisticsScore.setForeground(Color.BLACK);
    scoreLabel.setFont(new Font("Serif", Font.BOLD, TEXT_SIZE));
    endStatisticsScore.setVisible(true);
    add(endStatisticsScore);

    //TOTAL CURRENCY
    endStatisticsCurrency = new JLabel("Currency: "+currency);
    endStatisticsCurrency.setBounds(END_STATISTICS_X + (END_STATISTICS_WIDTH/2) - (COVER_ART_WIDTH/2), END_STATISTICS_Y+COVER_ART_HEIGHT+(4*END_STATISTIC_MARGIN), COVER_ART_WIDTH, END_STATISTIC_TEXT_HEIGHT);
    endStatisticsCurrency.setForeground(Color.BLACK);
    scoreLabel.setFont(new Font("Serif", Font.BOLD, TEXT_SIZE));
    endStatisticsCurrency.setVisible(true);
    add(endStatisticsCurrency);

    //FOOT NOTE
    endStatisticsNote = new JLabel("Exit Button (O) - Main Menu");
    endStatisticsNote.setBounds(END_STATISTICS_X + (END_STATISTICS_WIDTH/2) - (COVER_ART_WIDTH/2), END_STATISTICS_Y+END_STATISTICS_HEIGHT-40, COVER_ART_WIDTH,40);
    endStatisticsNote.setForeground(Color.BLACK);
    scoreLabel.setFont(new Font("Serif", Font.BOLD, TEXT_SIZE));
    endStatisticsNote.setVisible(true);
    add(endStatisticsNote);

    //COVER ART
    endStatisticsImg = new JLabel(new ImageIcon(resizeImage(img, COVER_ART_WIDTH, COVER_ART_HEIGHT)));
    endStatisticsImg.setBounds((int) (END_STATISTICS_X + (END_STATISTICS_WIDTH/2) - (COVER_ART_WIDTH/2)), END_STATISTICS_Y+50,COVER_ART_WIDTH,COVER_ART_HEIGHT);
    add(endStatisticsImg);
    add(endStatisticsBackground);
  }

  /**
   * setCoverArtLabel
   * Sets the cover art to be displayed on the screen during the game
   * Resizes the image file to fit the size of the JLabel
   * @param coverFile
   */
  public void setCoverArtLabel(File coverFile) {
    Image resizedImage = resizeImage(coverFile,COVER_ART_WIDTH,COVER_ART_HEIGHT);
    coverArtLabel = new JLabel(new ImageIcon(resizedImage));
    coverArtLabel.setBounds(COVER_ART_X, COVER_ART_Y, COVER_ART_WIDTH, COVER_ART_HEIGHT);
    add(coverArtLabel);
  }

  /**
   * Reads an image file and resizes it to desired dimensions
   * @param file
   * @param width
   * @param height
   * @return Resized Image as Image
   */
  public Image resizeImage(File file, int width, int height){
    Image image = null;
    try {
      image = ImageIO.read(file);
    } catch (IOException e) {
      e.printStackTrace();
    }
    Image resizedImage = image.getScaledInstance(width, height, Image.SCALE_DEFAULT);
    return resizedImage;
  }

  /**
   * setMultiplierLabel
   * Initialises the multiplier label to display the user's score multiplier
   * Also used to set a blank multiplier label when the user loses their score multiplier
   */
  public void setMultiplierLabel() {
    multiplierLabel = new JLabel();
    multiplierLabel.setBounds(MULTIPLIER_X, MULTIPLIER_Y, MULTIPLIER_WIDTH, MULTIPLIER_HEIGHT);
    multiplierLabel.setVisible(false);
    add(multiplierLabel);
  }

  /**
   * changeMultiplier
   * Called when the user gains a new score multiplier or loses their multiplier
   * Changes the multiplier label displayed on the screen
   * @param path the path of the multiplier asset to display
   */
  public void changeMultiplierLabel(String path) {
      multiplierLabel.setIcon(new ImageIcon(path));
      multiplierLabel.setVisible(true);
  }

  /**
   * setCurrencyLabel
   * Initialises tbe JLabel to display the currency stars
   */
  public void setCurrencyLabel() {
    currencyLabel = new JLabel();
    currencyLabel.setBounds(CURRENCY_X, CURRENCY_Y, CURRENCY_WIDTH, CURRENCY_HEIGHT);
    currencyLabel.setVisible(false);
    add(currencyLabel);
  }

  /**
   * Change currency label
   * Called when the user earns currency
   * Updates the amount of stars displayed on the screen
   * @param path the path to the asset corresponding to the amount of stars to be displayed
   */
  public void changeCurrencyLabel(String path) {
    currencyLabel.setIcon(new ImageIcon(path));
    currencyLabel.setVisible(true);
  }

  /**
   * setZeroPowerLabelInit
   * Initialises the zero power JLabel
   * @param path the path of the zero power image
   */
  public void setZeroPowerLabelInit(String path) {
    zeroPowerLabel = new JLabel(new ImageIcon(path));
    zeroPowerLabel.setBounds(ZERO_POWER_X, ZERO_POWER_Y, ZERO_POWER_WIDTH, ZERO_POWER_HEIGHT);
  }

  /**
   * setZeroPowerLabelVisible
   * Shows the zero power icon on the screen when zero power mode is active
   */
  public void setZeroPowerLabelVisible() {
    zeroPowerLabel.setVisible(true);
    add(zeroPowerLabel);
  }

  public void setZeroPowerLabelFalse() {
    zeroPowerLabel.setVisible(false);
  }

  /**
   * setScoreLabel
   * Initialises the Jlabel to display the user's current score
   * @param score
   */
  public void setScoreLabel(Integer score) {
    scoreLabel = new JLabel("Score: " + Integer.toString(score));
    scoreLabel.setFont(new Font("Serif", Font.BOLD, TEXT_SIZE));
    scoreLabel.setBounds(SCORE_X, SCORE_Y, SCORE_WIDTH, SCORE_HEIGHT);
    scoreLabel.setForeground(Color.white);
    scoreLabel.setVisible(true);
    add(scoreLabel);
  }

  /**
   * resetScoreLabel
   * Sets the value of the score being displayed
   * @param score the new score to be displayed
   */
  public void resetScoreLabel(Integer score) {
    scoreLabel.setText("Score: " + Integer.toString(score));
  }

  /**
   * setStreakLabel
   * Initialises the JLabel to display the user's note streak
   */
  public void setStreakLabel() {
    streakLabel = new JLabel("Streak:  " + Integer.toString(0));
    streakLabel.setFont(new Font("Serif", Font.BOLD, TEXT_SIZE));
    streakLabel.setBounds(STREAK_X,STREAK_Y, STREAK_WIDTH, STREAK_HEIGHT);
    streakLabel.setForeground(Color.white);
    add(streakLabel);
  }

  /**
   * resetStreakLabel
   * Sets the value of the streak being displayed
   * @param streak the new streak to display
   */
  public void resetStreakLabel(Integer streak) {
    streakLabel.setText("Streak:  " + streak);
  }

  /**
   * noteInit
   * Initialises the notes to be shown on the fretboard when the user presses a note button
   * Initialises the coloured note image for when the user collects a note
   */
  public void noteInit() {
    // WHITE1 - 0 in controller
    noteLabel = new JLabel(new ImageIcon(FRETBOARD_WHITE));
    noteLabel.setBounds(FRETBOARD_LEFT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteLabel.setVisible(false);
    activeNotes[0] = noteLabel;

    noteCollected = new JLabel(new ImageIcon(FRETBOARD_WHITE_COLLECTED));
    noteCollected.setBounds(FRETBOARD_LEFT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteCollected.setVisible(false);
    collectedNotes[0] = noteCollected;

    //BLACK1 - 1 in controller
    noteLabel = new JLabel(new ImageIcon(FRETBOARD_BLACK));
    noteLabel.setBounds(FRETBOARD_LEFT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteLabel.setVisible(false);
    activeNotes[1] = noteLabel;

    noteCollected = new JLabel(new ImageIcon(FRETBOARD_BLACK_COLLECTED));
    noteCollected.setBounds(FRETBOARD_LEFT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteCollected.setVisible(false);
    collectedNotes[1] = noteCollected;

    //BLACK2 - 2 in controller
    noteLabel = new JLabel(new ImageIcon(FRETBOARD_BLACK));
    noteLabel.setBounds(FRETBOARD_MIDDLE_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteLabel.setVisible(false);
    activeNotes[2] = noteLabel;

    noteCollected = new JLabel(new ImageIcon(FRETBOARD_BLACK_COLLECTED));
    noteCollected.setBounds(FRETBOARD_MIDDLE_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteCollected.setVisible(false);
    collectedNotes[2] = noteCollected;

    //BLACK3 - 3 in controller
    noteLabel = new JLabel(new ImageIcon(FRETBOARD_BLACK));
    noteLabel.setBounds(FRETBOARD_RIGHT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteLabel.setVisible(false);
    activeNotes[3] = noteLabel;

    noteCollected = new JLabel(new ImageIcon(FRETBOARD_BLACK_COLLECTED));
    noteCollected.setBounds(FRETBOARD_RIGHT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteCollected.setVisible(false);
    collectedNotes[3] = noteCollected;

    //WHITE2 - 4 in controller
    noteLabel = new JLabel(new ImageIcon(FRETBOARD_WHITE));
    noteLabel.setBounds(FRETBOARD_MIDDLE_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteLabel.setVisible(false);
    activeNotes[4] = noteLabel;

    noteCollected = new JLabel(new ImageIcon(FRETBOARD_WHITE_COLLECTED));
    noteCollected.setBounds(FRETBOARD_MIDDLE_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteCollected.setVisible(false);
    collectedNotes[4] = noteCollected;

    //WHITE3 - 5 in controller
    noteLabel = new JLabel(new ImageIcon(FRETBOARD_WHITE));
    noteLabel.setBounds(FRETBOARD_RIGHT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteLabel.setVisible(false);
    activeNotes[5] = noteLabel;

    noteCollected = new JLabel(new ImageIcon(FRETBOARD_WHITE_COLLECTED));
    noteCollected.setBounds(FRETBOARD_RIGHT_X, FRETBOARD_Y, FRETBOARD_NOTE_WIDTH, FRETBOARD_NOTE_HEIGHT);
    noteCollected.setVisible(false);
    collectedNotes[5] = noteCollected;

    for (int i = 0; i < TOTAL_NOTE_BUTTONS; i ++) {
      add(activeNotes[i]);
      add(collectedNotes[i]);
    }
  }

  /**
   * noteDisplay
   * Displays a note on the fretboard when the user presses the button
   * Note corresponds with the button pressed on the guitar
   * @param display true if note should be displayed, false otherwise
   * @param pressedButton the button pressed by the user
   */
  public void noteDisplay(boolean display, int pressedButton) {
    if (display) {
      activeNotes[pressedButton].setVisible(true);
    } else {
      if(noteLabel != null) {
        for (int i = 0; i < pressedButton; i++)
          activeNotes[i].setVisible(false);
      }
    }
  }

  /**
   * noteCollected
   * Displays a coloured version of a note on the fretboard if a note has been collected
   * Note displayed on the fretboard corresponds to the note collected
   * @param display true if the collected note should be displayed, false otherwise
   * @param pressedButton the button pressed by the user when collecting the note
   */
  public void noteCollected(boolean display, int pressedButton) {
    if (display) {
      collectedNotes[pressedButton].setVisible(true);
    } else {
      if(noteCollected != null) {
        for (int i = 0; i < pressedButton; i++)
          collectedNotes[i].setVisible(false);
      }
    }
  }

  /**
   * addNote
   * @param note the note to be added to the highway, passed from the model
   */
  public void addNote(Note note){
    notes.add(note);
  }

  /**
    * paintComponent
    * Draws all necessary GUI elements on the JPanel
    * Removes a note if it has passed a certain boundary
    * @param g: The the graphics object associated with the JPanel
    */
  @Override
  public synchronized void paintComponent(Graphics g) {

    super.paintComponent(g);
    //Draw the background animation frame depending on the current frame/10%(number of frames in the animation)
    g.drawImage(this.bg[((frame/this.backgroundFrameDelay)%this.backgroundFrameCount)], 0, 0, null);
    int len = notes.size();


    for(int i=len-1; i>-1; i--){
      // Draw the note
      notes.get(i).paintComponent(g);

        // Remove from the notes ArrayList as no longer needed
      if(notes.get(i).getY() > DROP_NOTE_BOUND || notes.get(i).collected)
        notes.remove(i);
      }

    frame++;
    }

  }

<file_sep>/src/TutorialModeView.java
import javax.swing.*;
import java.util.ArrayList;
import javax.swing.JLabel;

/**
 * TutorialModeView.
 *
 * @author <NAME>
 * @version 1.01, March 2019.
 */
public class TutorialModeView extends JPanel {

  private ArrayList<ImageIcon> pictureIcons;

  JLabel currentPicture = null;
  ArrayList<JLabel> pictureLabels = new ArrayList<JLabel>();

  /**
   * Alters the GUI by taking commands from a model class
   *
   * @param pictureIcons: A list of pictures to display graphically
   */
  public TutorialModeView (ArrayList<ImageIcon> pictureIcons) {

    this.pictureIcons = pictureIcons;


    setBounds(0, 0, 1000, 500);

    for (ImageIcon pictureIcon : pictureIcons) {
      JLabel label = new JLabel(pictureIcon);
      label.setBounds(50, 50, 400, 400);
      add(label);
      label.setVisible(false);
      pictureLabels.add(label);
    }

    pictureLabels.get(0).setVisible(true);
    currentPicture = pictureLabels.get(0);

    setVisible(true);
  }


  /**
   * Switches images to the left, replacing with next picture
   */
  public void leftMovement() {

    for (int i = 0; i < pictureLabels.size(); i++) {

      if (pictureLabels.get(i) == currentPicture && i != 0) {

        pictureLabels.get(i).setVisible(false);
        pictureLabels.get(i-1).setVisible(true);
        currentPicture = pictureLabels.get(i-1);

        setVisible(true);

        break;

      } else if (pictureLabels.get(i) == currentPicture && i == 0){

        break;
      }
    }
  }



  /**
   * Switches images to the right, replacing with next picture
   */
  public void rightMovement() {

    for (int i = 0; i < pictureLabels.size(); i++) {

      if (pictureLabels.get(i) == currentPicture && i != pictureLabels.size()-1) {

        pictureLabels.get(i).setVisible(false);
        pictureLabels.get(i + 1).setVisible(true);
        currentPicture = pictureLabels.get(i + 1);

        setVisible(true);

        break;

      } else if (pictureLabels.get(i) == currentPicture && i == pictureLabels.size()-1) {

        break;

      }
    }

  }

}
<file_sep>/src/StoreManagerView.java
import java.awt.*;
import javax.swing.*;
import java.io.*;

/**
 * StoreManagerView.
 *
 * @author  <NAME>
 * @version 2.3, March 2019
 *
 */
public class StoreManagerView extends JFrame {

  static File titleFile = null;
  static File coverArtFile = null;
  static File musicFile = null;

  static JTextField titleField = new JTextField(10);
  static JTextField coverArtField = new JTextField(10);
  static JTextField musicField = new JTextField(10);

  private static final int STORE_WIDTH  = 300;
  private static final int STORE_HEIGHT = 200;

  /**
   * Sets up the JFrame.
   * @param titleButton: Title browse controller
   * @param coverArtButton: Cover browse controller
   * @param songButton: Midi browse controller
   * @param saveButton: Save button controller
   */
  public StoreManagerView ( StoreManagerController titleButton,
      StoreManagerController coverArtButton,
      StoreManagerController songButton,
      StoreManagerController saveButton) {

    setTitle("Store Manager");

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(STORE_WIDTH, STORE_HEIGHT);

    // Creating components to populate the frame
    JLabel titleLabel = new JLabel("Title:       ");
    JLabel coverArtLabel = new JLabel("Cover art:");
    JLabel musicLabel = new JLabel("Music:     ");


    JButton titleBrowse = new JButton("Browse");
    JButton coverArtBrowse = new JButton("Browse");
    JButton musicBrowse = new JButton("Browse");


    // Creating the three sub-top panels to the top panel
    JPanel topPanel = new JPanel(new BorderLayout());

    JPanel topFirstPanel = panelCreator(titleLabel, titleField, titleBrowse);
    JPanel topSecondPanel = panelCreator(coverArtLabel, coverArtField, coverArtBrowse);
    JPanel topThirdPanel = panelCreator(musicLabel, musicField, musicBrowse);

    topPanel.add(BorderLayout.NORTH, topFirstPanel);
    topPanel.add(BorderLayout.CENTER, topSecondPanel);
    topPanel.add(BorderLayout.SOUTH, topThirdPanel);


    // Creating the bottom panel and adding the 'save' button
    JPanel bottomPanel = new JPanel();
    JButton save = new JButton("Save");
    bottomPanel.add(save);


    // Adding the main top and bottom panels to the frame
    getContentPane().add(BorderLayout.NORTH, topPanel);
    getContentPane().add(BorderLayout.SOUTH, bottomPanel);


    titleBrowse.addActionListener(titleButton);
    coverArtBrowse.addActionListener(coverArtButton);
    musicBrowse.addActionListener(songButton);
    save.addActionListener(saveButton);

  }

  /**
   * Creates a JPanel
   * @param label:     A JLabel to add to the JPanel
   * @param textField: A JTextField to add to the JPanel
   * @param button:    A JButton to add to the JPanel
   * @return           The JPanel containing all the passed parameters
   */
  public static JPanel panelCreator (JLabel label, JTextField textField, JButton button) {
    JPanel panel = new JPanel(new BorderLayout());
    panel.add(BorderLayout.LINE_START, label);
    panel.add(BorderLayout.CENTER, textField);
    panel.add(BorderLayout.LINE_END, button);
    return panel;
  }


  public static void setTitleTitle (String filePath) { titleField.setText(filePath); }

  public static void setCoverArtTitle (String filePath) { coverArtField.setText(filePath); }

  public static void setMusicTitle (String filePath) { musicField.setText(filePath); }


}<file_sep>/src/Handler.java
import java.io.*;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * Handler.
 *
 * @author  <NAME>
 * @version 1.17, March 2019.
 */
public class Handler implements Runnable {

  private Socket sck;
  final int BUFFER_SIZE = 4092;

  Handler(Socket sck) {
    this.sck = sck;
  }

  /**
   * Downloads/uploads files to/from clients.
   */
  public void run() {
    try {
      // Client socket streams
      final DataInputStream dataIn = new DataInputStream(sck.getInputStream());
      final DataOutputStream dataOut = new DataOutputStream(sck.getOutputStream());

      // Parsing UTF - getting method
      String header = dataIn.readUTF();
      String[] headers = header.split("/");
      String method = headers[0].toUpperCase();
      char methodType = method.charAt(0);

      // Getting file name (if uploading or downloading)
      String fileName = "";
      if (methodType == 'U' || methodType == 'D') {
        fileName = headers[1];
      }

      // Processing request
      if (methodType == 'U') {
        long fileSize = dataIn.readLong();
        processUpload(method, dataIn, fileName, fileSize);
      } else if (methodType == 'D') {
        processDownload(method, dataOut, fileName);
        dataIn.close();
      } else if (method.equals("LIST_DIRECTORY")) {
        processListing(dataOut);
      }

      sck.close();

    } catch (Exception exn) {
      System.out.println(exn);
      System.exit(1);
    }
  }

  /**
   * Processes an upload request (sending files from client to server).
   *
   * @param method: Method type. Either 'UPLOAD_BUNDLE' or 'UPLOAD_PREVIEW'.
   * @param dataIn: DataInputStream to read from.
   * @param fileName: Name of the file to upload.
   * @param fileSize: Size of file to upload (bytes).
   */
  public void processUpload(String method, DataInputStream dataIn, String fileName, long fileSize) {
    // Building file path string
    String filePath = "";
    try {
      filePath = getFilePath(method, fileName);
    } catch (InvalidMethodException exn) {
      System.out.println(exn);
      System.exit(1);
    }

    // Processing the upload - synchronized to prevent 'connection abort: recv failed'
    synchronized (this) {
      try {
        // Stream for file to be written to (local directory on server)
        BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream(filePath));

        // Reading file in from dataIn and writing it to fileOut stream
        int n;
        byte[] buf = new byte[BUFFER_SIZE];
        while (fileSize > 0
            && (n = dataIn.read(buf, 0, (int) Math.min(buf.length, fileSize))) != -1) {
          fileOut.write(buf, 0, n);
          fileSize -= 1;
        }

        // Cleaning up
        fileOut.close();

      } catch (Exception exn) {
        System.out.println(exn);
        System.exit(1);
      }
    }
  }

  /**
   * Processes a download request (retrieving files from server to client).
   *
   * @param method: Download method. Either 'DOWNLOAD_BUNDLE' or 'DOWNLOAD_PREVIEW'.
   * @param fileName: Name of file to download.
   */
  public void processDownload(String method, DataOutputStream dataOut, String fileName) {
    // Building file path string
    String filePath = "";
    try {
      filePath = getFilePath(method, fileName);
    } catch (InvalidMethodException exn) {
      System.out.println(exn);
      System.exit(1);
    }

    // Processing the download - synchronized to prevent 'connection abort: recv failed'
    synchronized (this) {
      try {
        // Reading file into byte array
        Path fileLocation = Paths.get(filePath);
        byte[] data = Files.readAllBytes(fileLocation);

        // Writing file from byte array to dataOut stream
        dataOut.writeLong(data.length);
        dataOut.write(data, 0, data.length);
        dataOut.flush();

      } catch (Exception exn) {
        System.out.println(exn);
        System.exit(1);
      }
    }
  }

  /**
   * Builds (local) file path string from request method and file name.
   *
   * @param method: Request method (UPLOAD/DOWNLOAD + _BUNDLE/_PREVIEW)
   * @param fileName: File name for request (name of file to be uploaded/downloaded to/from
   * server).
   * @throws InvalidMethodException: Thrown when provided method is invalid.
   * @return: File path to requested file.
   */
  public static String getFilePath(String method, String fileName) throws InvalidMethodException {
    // Building file path string
    String cd = System.getProperty("user.dir");
    if (method.equals("DOWNLOAD_BUNDLE") || method.equals("UPLOAD_BUNDLE")) {
      return cd + "/bundle_files/" + fileName;
    } else if (method.equals("DOWNLOAD_PREVIEW") || method.equals("UPLOAD_PREVIEW")) {
      return cd + "/preview_files/" + fileName;
    } else {
      throw new InvalidMethodException("Invalid method provided.");
    }
  }

  /**
   * Processes a listing request to the server.
   *
   * @param dataOut: DataOutputStream to write directory listings to.
   */
  public void processListing(DataOutputStream dataOut) {
    File previewDir = new File(System.getProperty("user.dir") + "/preview_files/");
    String[] previews = previewDir.list();

    synchronized (this) {
      try {
        // Writing song names to textOut
        for (String preview : previews) {
          dataOut.writeUTF(preview);
        }
        dataOut.writeUTF("END");
        dataOut.flush();

        // Cleaning up
        sck.close();
      } catch (Exception exn) {
        System.out.println(exn);
        System.exit(1);
      }
    }

  }
}