<commit_before>package de.adesso.anki;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

import de.adesso.anki.messages.Message;

/**
 * Manages a Bluetooth LE connection by communicating with the Node.js socket.
 * 
 * @author <NAME> <<EMAIL>>
 */
@SuppressWarnings("rawtypes")
public class AnkiConnector {
  
  private Socket socket;
  
  private PrintWriter writer;
  private NotificationReader reader;
  
  private Multimap<Vehicle, MessageListener> listeners;
  
  public AnkiConnector(String host, int port) throws IOException {
    socket = new Socket(host, port);
    writer = new PrintWriter(socket.getOutputStream(), true);
    reader = new NotificationReader(socket.getInputStream());
    
    listeners = ArrayListMultimap.create();
  }
  
  public AnkiConnector(String host) throws IOException {
    this(host, 5000);
  }
  
  public List<Vehicle> findVehicles() {
    writer.println("SCAN");
    List<Vehicle> foundVehicles = new ArrayList<>();
    boolean expectingResponse = true;
    while (expectingResponse)
    {
      String response = reader.waitFor("SCAN;");
      if (response.equals("SCAN;COMPLETED")) {
        expectingResponse = false;
      }
      else {
        String[] parts = response.split(";");
        
        String address = parts[1];
        String manufacturerData = parts[2];
        String localName = parts[3];
        
        foundVehicles.add(new Vehicle(this, address, manufacturerData, localName));
      }
    }
    return foundVehicles;
  }

  public void connect(Vehicle vehicle) throws InterruptedException {
    writer.println("CONNECT;"+vehicle.getAddress());
    String response = reader.waitFor("CONNECT;");
    
    if (response.equals("CONNECT;ERROR")) {
      throw new RuntimeException("connect failed");
    }
    
    reader.addListener((line) -> {
      if (line.startsWith(vehicle.getAddress())) {
        String messageString = line.replaceFirst(vehicle.getAddress()+";", "");
        Message message = Message.parse(messageString);
        fireMessageReceived(vehicle, message);
      }
    });
  }
  
  public synchronized void sendMessage(Vehicle vehicle, Message message) {
    writer.println(vehicle.getAddress() + ";" + message.toHex());
    writer.flush();
  }
  
  public void addMessageListener(Vehicle vehicle, MessageListener<? extends Message> listener) {
    listeners.put(vehicle, listener);
  }
  
  public void removeMessageListener(Vehicle vehicle, MessageListener<? extends Message> listener) {
    listeners.remove(vehicle, listener);
  }
  
  @SuppressWarnings("unchecked")
  public void fireMessageReceived(Vehicle vehicle, Message message) {
    for (MessageListener l : listeners.get(vehicle)) {
      l.messageReceived(message);
    }
  }

  public void disconnect(Vehicle vehicle) {
    writer.println("DISCONNECT;"+vehicle.getAddress());
    reader.waitFor("DISCONNECT;");
  }

  public void close() {
    reader.close();<commit_msg>Synchronize AnkiConnector methods to avoid mixed calls (#7)<commit_after>package de.adesso.anki;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

import de.adesso.anki.messages.Message;

/**
 * Manages a Bluetooth LE connection by communicating with the Node.js socket.
 * 
 * @author <NAME> <<EMAIL>>
 */
@SuppressWarnings("rawtypes")
public class AnkiConnector {
  
  private Socket socket;
  
  private PrintWriter writer;
  private NotificationReader reader;
  
  private Multimap<Vehicle, MessageListener> listeners;
  
  public AnkiConnector(String host, int port) throws IOException {
    socket = new Socket(host, port);
    writer = new PrintWriter(socket.getOutputStream(), true);
    reader = new NotificationReader(socket.getInputStream());
    
    listeners = ArrayListMultimap.create();
  }
  
  public AnkiConnector(String host) throws IOException {
    this(host, 5000);
  }
  
  public synchronized List<Vehicle> findVehicles() {
    writer.println("SCAN");
    List<Vehicle> foundVehicles = new ArrayList<>();
    boolean expectingResponse = true;
    while (expectingResponse)
    {
      String response = reader.waitFor("SCAN;");
      if (response.equals("SCAN;COMPLETED")) {
        expectingResponse = false;
      }
      else {
        String[] parts = response.split(";");
        
        String address = parts[1];
        String manufacturerData = parts[2];
        String localName = parts[3];
        
        foundVehicles.add(new Vehicle(this, address, manufacturerData, localName));
      }
    }
    return foundVehicles;
  }

  public synchronized void connect(Vehicle vehicle) throws InterruptedException {
    writer.println("CONNECT;"+vehicle.getAddress());
    String response = reader.waitFor("CONNECT;");
    
    if (response.equals("CONNECT;ERROR")) {
      throw new RuntimeException("connect failed");
    }
    
    reader.addListener((line) -> {
      if (line.startsWith(vehicle.getAddress())) {
        String messageString = line.replaceFirst(vehicle.getAddress()+";", "");
        Message message = Message.parse(messageString);
        fireMessageReceived(vehicle, message);
      }
    });
  }
  
  public synchronized void sendMessage(Vehicle vehicle, Message message) {
    writer.println(vehicle.getAddress() + ";" + message.toHex());
    writer.flush();
  }
  
  public void addMessageListener(Vehicle vehicle, MessageListener<? extends Message> listener) {
    listeners.put(vehicle, listener);
  }
  
  public void removeMessageListener(Vehicle vehicle, MessageListener<? extends Message> listener) {
    listeners.remove(vehicle, listener);
  }
  
  @SuppressWarnings("unchecked")
  public void fireMessageReceived(Vehicle vehicle, Message message) {
    for (MessageListener l : listeners.get(vehicle)) {
      l.messageReceived(message);
    }
  }

  public synchronized void disconnect(Vehicle vehicle) {
    writer.println("DISCONNECT;"+vehicle.getAddress());
    reader.waitFor("DISCONNECT;");
  }

  public void close() {
    reader.close();
{'fraction_non_alphanumeric': 0.117077045274027, 'fraction_numerical': 0.0023828435266084196, 'mean_word_length': 3.6602516654330124, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4547503', 'n_tokens_mistral': 1780, 'n_tokens_neox': 1794, 'n_words': 399}