<commit_before>package com.matchandtrade.rest.v1.transformer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.matchandtrade.persistence.entity.ItemEntity;
import com.matchandtrade.persistence.entity.TradeEntity;
import com.matchandtrade.persistence.entity.TradeMembershipEntity;
import com.matchandtrade.persistence.facade.ItemRepositoryFacade;
import com.matchandtrade.persistence.facade.TradeMembershipRepositoryFacade;
import com.matchandtrade.persistence.facade.TradeRepositoryFacade;

@Component
public class TradeMaximizerTransformer {
	
	@Autowired
	private ItemRepositoryFacade itemRepositoryFacade;
	@Autowired
	private TradeMembershipRepositoryFacade tradeMembershipRepositoryFacade;
	@Autowired
	private TradeRepositoryFacade tradeRepositoryFacade;

	/**
	 * Helper class to temporarily hold parsed values from a trade line 
	 */
	private class TradeLinePojo {
		public Integer offeringTradeMembershipId;
		public Integer offeringItemId;
		public Integer receivingTradeMembershipId;
		public Integer receivingItemId;
		public Integer sendingTradeMembershipId;
	}

	/**
	 * Transform the output of Trade Maximizer into CSV.
	 * Items not traded are omitted.
	 *  
	 * @param tradeMaximizerOutput
	 * @return trade result in CSV format
	 * @throws IOException
	 */
	public String toCsv(Integer tradeId, String tradeMaximizerOutput) throws IOException {
		List<String> lines = transformTradeMaximizerToList(tradeMaximizerOutput);

		// Sort trade lines for better CSV presentation 
		sortTradeLinesByOfferingTradeMembershipAndOfferingItemId(lines);
		
		CSVFormat formatter = CSVFormat.DEFAULT
				.withRecordSeparator("\n")
				.withCommentMarker('#')
				.withHeader("user_id", "user_name", "item_id",  "item_name", "receives",
							"receiving_from_user_id", "receiving_from_user_name", "receiving_item_id", "receiving_item_name", "sends_to",
							"sending_to_user_id", "sending_to_user_name");
		
		StringBuilder csvOutput = new StringBuilder();
		CSVPrinter csvPrinter = formatter.print(csvOutput);
		// Tracks the total of traded items
		int tradedItemsCount = 0;
		
		for (String line : lines) {
			TradeLinePojo linePojo = transformLine(line);
			//Items not traded "receivingTradeMembershipId == null" are omitted
			if (linePojo.receivingTradeMembershipId == null) {
				continue;
			}
			
			List<Object> csvRecord = new ArrayList<>();
			TradeMembershipEntity offeringMembership = tradeMembershipRepositoryFacade.get(linePojo.offeringTradeMembershipId);
			csvRecord.add(offeringMembership.getUser().getUserId());
			csvRecord.add(offeringMembership.getUser().getName());
			ItemEntity offeringItem = itemRepositoryFacade.get(linePojo.offeringItemId);
			csvRecord.add(offeringItem.getItemId());
			csvRecord.add(offeringItem.getName());
			if (linePojo.receivingItemId != null) {
				tradedItemsCount++;
				csvRecord.add(":RECEIVES:");
				TradeMembershipEntity receivingMembership = tradeMembershipRepositoryFacade.get(linePojo.receivingTradeMembershipId);
				csvRecord.add(receivingMembership.getUser().getUserId());
				csvRecord.add(receivingMembership.getUser().getName());
				ItemEntity receivingItem = itemRepositoryFacade.get(linePojo.receivingItemId);
				csvRecord.add(receivingItem.getItemId());
				csvRecord.add(receivingItem.getName());
				csvRecord.add(":SENDS:");
				TradeMembershipEntity sendingMembership = tradeMembershipRepositoryFacade.get(linePojo.sendingTradeMembershipId);
				csvRecord.add(sendingMembership.getUser().getUserId());
				csvRecord.add(sendingMembership.getUser().getName());
			}
			csvPrinter.printRecord(csvRecord);
		}

		// Handles the Summary portion
		printSummary(tradeId, lines.size(), tradedItemsCount, csvPrinter);
		csvPrinter.close();
		
		return csvOutput.toString();
	}

	private void printSummary(Integer tradeId, Integer totalOfItems, int totalOfTradedItems, CSVPrinter csvPrinter) throws IOException {
		TradeEntity trade = tradeRepositoryFacade.get(tradeId);
		csvPrinter.println();
		csvPrinter.printComment("--------------------------------");
		csvPrinter.printComment("Summary of Trade [" + trade.getTradeId() + " : " + trade.getName() + "]");
		csvPrinter.printComment("Total of items: " + totalOfItems);
		csvPrinter.printComment("Total of traded items: " + totalOfTradedItems);
		csvPrinter.printComment("Total of items not traded: " + (totalOfItems - totalOfTradedItems));
		csvPrinter.printComment("--------------------------------");
		csvPrinter.printComment("");
		csvPrinter.printComment("Below is an example to help you understand the results:");
		csvPrinter.printComment("Sample row:  1,Alice,10,Ticket to Ride,:RECEIVES:,2,Bob,11,Power Grid,:SENDS:,3,Charlie,1,Pandemic");
		csvPrinter.printComment("Explanation: Alice receives Bob's Power Grid and sends her Ticket to Ride to Charlie");
	}

	/**
	 * Sort trade lines by offeringTradeMembership and itemId <commit_msg>Corrected example in csv results<commit_after>package com.matchandtrade.rest.v1.transformer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.matchandtrade.persistence.entity.ItemEntity;
import com.matchandtrade.persistence.entity.TradeEntity;
import com.matchandtrade.persistence.entity.TradeMembershipEntity;
import com.matchandtrade.persistence.facade.ItemRepositoryFacade;
import com.matchandtrade.persistence.facade.TradeMembershipRepositoryFacade;
import com.matchandtrade.persistence.facade.TradeRepositoryFacade;

@Component
public class TradeMaximizerTransformer {
	
	@Autowired
	private ItemRepositoryFacade itemRepositoryFacade;
	@Autowired
	private TradeMembershipRepositoryFacade tradeMembershipRepositoryFacade;
	@Autowired
	private TradeRepositoryFacade tradeRepositoryFacade;

	/**
	 * Helper class to temporarily hold parsed values from a trade line 
	 */
	private class TradeLinePojo {
		public Integer offeringTradeMembershipId;
		public Integer offeringItemId;
		public Integer receivingTradeMembershipId;
		public Integer receivingItemId;
		public Integer sendingTradeMembershipId;
	}

	/**
	 * Transform the output of Trade Maximizer into CSV.
	 * Items not traded are omitted.
	 *  
	 * @param tradeMaximizerOutput
	 * @return trade result in CSV format
	 * @throws IOException
	 */
	public String toCsv(Integer tradeId, String tradeMaximizerOutput) throws IOException {
		List<String> lines = transformTradeMaximizerToList(tradeMaximizerOutput);

		// Sort trade lines for better CSV presentation 
		sortTradeLinesByOfferingTradeMembershipAndOfferingItemId(lines);
		
		CSVFormat formatter = CSVFormat.DEFAULT
				.withRecordSeparator("\n")
				.withCommentMarker('#')
				.withHeader("user_id", "user_name", "item_id",  "item_name", "receives",
							"receiving_from_user_id", "receiving_from_user_name", "receiving_item_id", "receiving_item_name", "sends_to",
							"sending_to_user_id", "sending_to_user_name");
		
		StringBuilder csvOutput = new StringBuilder();
		CSVPrinter csvPrinter = formatter.print(csvOutput);
		// Tracks the total of traded items
		int tradedItemsCount = 0;
		
		for (String line : lines) {
			TradeLinePojo linePojo = transformLine(line);
			//Items not traded "receivingTradeMembershipId == null" are omitted
			if (linePojo.receivingTradeMembershipId == null) {
				continue;
			}
			
			List<Object> csvRecord = new ArrayList<>();
			TradeMembershipEntity offeringMembership = tradeMembershipRepositoryFacade.get(linePojo.offeringTradeMembershipId);
			csvRecord.add(offeringMembership.getUser().getUserId());
			csvRecord.add(offeringMembership.getUser().getName());
			ItemEntity offeringItem = itemRepositoryFacade.get(linePojo.offeringItemId);
			csvRecord.add(offeringItem.getItemId());
			csvRecord.add(offeringItem.getName());
			if (linePojo.receivingItemId != null) {
				tradedItemsCount++;
				csvRecord.add(":RECEIVES:");
				TradeMembershipEntity receivingMembership = tradeMembershipRepositoryFacade.get(linePojo.receivingTradeMembershipId);
				csvRecord.add(receivingMembership.getUser().getUserId());
				csvRecord.add(receivingMembership.getUser().getName());
				ItemEntity receivingItem = itemRepositoryFacade.get(linePojo.receivingItemId);
				csvRecord.add(receivingItem.getItemId());
				csvRecord.add(receivingItem.getName());
				csvRecord.add(":SENDS:");
				TradeMembershipEntity sendingMembership = tradeMembershipRepositoryFacade.get(linePojo.sendingTradeMembershipId);
				csvRecord.add(sendingMembership.getUser().getUserId());
				csvRecord.add(sendingMembership.getUser().getName());
			}
			csvPrinter.printRecord(csvRecord);
		}

		// Handles the Summary portion
		printSummary(tradeId, lines.size(), tradedItemsCount, csvPrinter);
		csvPrinter.close();
		
		return csvOutput.toString();
	}

	private void printSummary(Integer tradeId, Integer totalOfItems, int totalOfTradedItems, CSVPrinter csvPrinter) throws IOException {
		TradeEntity trade = tradeRepositoryFacade.get(tradeId);
		csvPrinter.println();
		csvPrinter.printComment("--------------------------------");
		csvPrinter.printComment("Summary of Trade [" + trade.getTradeId() + " : " + trade.getName() + "]");
		csvPrinter.printComment("Total of items: " + totalOfItems);
		csvPrinter.printComment("Total of traded items: " + totalOfTradedItems);
		csvPrinter.printComment("Total of items not traded: " + (totalOfItems - totalOfTradedItems));
		csvPrinter.printComment("--------------------------------");
		csvPrinter.printComment("");
		csvPrinter.printComment("Below is an example to help you understand the results:");
		csvPrinter.printComment("Sample row:  1,Alice,10,Ticket to Ride,:RECEIVES:,2,Bob,11,Power Grid,:SENDS:,3,Charlie");
		csvPrinter.printComment("Explanation: Alice receives Bob's Power Grid and sends her Ticket to Ride to Charlie");
	}

	/**
	 * Sort trade lines by offeringTradeMembership and itemId 
{'fraction_non_alphanumeric': 0.11219702892885067, 'fraction_numerical': 0.0018569194683346365, 'mean_word_length': 5.399624765478424, 'pattern_counts': {'":': 4, '<': 9, '<?xml version=': 0, '>': 9, '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': '1922505', 'n_tokens_mistral': 3359, 'n_tokens_neox': 2994, 'n_words': 584}