<commit_before>package org.openlca.io.xls;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.function.Consumer;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.openlca.core.database.IDatabase;
import org.openlca.core.matrix.MatrixData;
import org.openlca.core.matrix.format.ByteMatrixReader;
import org.openlca.core.matrix.format.MatrixReader;
import org.openlca.core.matrix.io.MatrixExport;
import org.openlca.core.matrix.io.index.IxContext;
import org.openlca.core.matrix.io.index.IxEnviIndex;
import org.openlca.core.matrix.io.index.IxFlow;
import org.openlca.core.matrix.io.index.IxImpact;
import org.openlca.core.matrix.io.index.IxImpactIndex;
import org.openlca.core.matrix.io.index.IxLocation;
import org.openlca.core.matrix.io.index.IxProvider;
import org.openlca.core.matrix.io.index.IxTechIndex;

public class MatrixExcelExport extends MatrixExport {

	private boolean skipZeros = true;

	public MatrixExcelExport(IDatabase db, File folder, MatrixData data) {
		super(db, folder, data);
	}

	public MatrixExcelExport skipZeros(boolean b) {
		this.skipZeros = b;
		return this;
	}

	@Override
	protected void write(MatrixReader matrix, String name) {
		if (matrix == null || name == null)
			return;
		sheetOf(name, sheet -> {
			for (int i = 0; i < matrix.rows(); i++) {
				var row = sheet.createRow(i);
				for (int j = 0; j < matrix.columns(); j++) {
					double val = matrix.get(i, j);
					if (skipZeros && val == 0)
						continue;
					row.createCell(j).setCellValue(val);
				}
			}
		});
	}

	@Override
	protected void write(double[] vector, String name) {
		if (vector == null || name == null)
			return;
		sheetOf(name, sheet -> {
			for (int i = 0; i < vector.length; i++) {
				sheet.createRow(i)
					.createCell(0)
					.setCellValue(vector[i]);
			}
		});
	}

	@Override
	protected void write(ByteMatrixReader matrix, String name) {
		if (matrix == null || name == null)
			return;
		sheetOf(name, sheet -> {
			for (int i = 0; i < matrix.rows(); i++) {
				var row = sheet.createRow(i);
				for (int j = 0; j < matrix.columns(); j++) {
					byte val = matrix.get(i, j);
					if (skipZeros && val == 0)
						continue;
					row.createCell(j).setCellValue(val);
				}
			}
		});
	}

	@Override
	public void writeIndices() {

		var context = IxContext.of(db);

		// tech. index
		if (data.techIndex != null) {
			var techIdx = IxTechIndex.of(data.techIndex, context);
			sheetOf("index_A", sheet -> {
				for (int i = 0; i < techIdx.size(); i++) {
					var row = sheet.createRow(i);
					var item = techIdx.items().get(i);
					Excel.cell(row, 0, item.index());
					next(item.provider(), row);
					next(item.flow(), row, 5);
				}
			});
		}

		// flow index
		if (data.enviIndex != null) {
			var enviIdx = IxEnviIndex.of(data.enviIndex, context);
			sheetOf("index_B", sheet -> {
				for (int i = 0; i < enviIdx.size(); i++) {
					var row = sheet.createRow(i);
					var item = enviIdx.items().get(i);
					Excel.cell(row, 0, item.index());
					next(item.flow(), row, 1);
					next(item.location(), row);
				}
			});
		}

		// impact index
		if (data.impactIndex != null) {
			var impactIdx = IxImpactIndex.of(data.impactIndex);
			sheetOf("index_C", sheet -> {
				for (int i = 0; i < impactIdx.size(); i++) {
					var row = sheet.createRow(i);
					var item = impactIdx.items().get(i);
					Excel.cell(row, 0, item.index());
					next(item.impact(), row);
				}
			});
		}
	}

	private void sheetOf(String name, Consumer<Sheet> fn) {
		try (var wb = new SXSSFWorkbook(-1)) {
			var sheet = wb.createSheet(name);
			fn.accept(sheet);
			var file = new File(folder, name + ".xlsx");
			try (var stream = new FileOutputStream(file)) {
				wb.write(stream);
				wb.dispose();
			}
		} catch (IOException e) {
			throw new RuntimeException(
				"failed to write matrix " + name, e);
		}
	}

	private void next(IxProvider p, Row row) {
		if (p == null)
			return;
		Excel.cell(row, 1, p.id());
		Excel.cell(row, 2, p.name());
		Excel.cell(row, 3, p.category());
		Excel.cell(row, 4, p.locationCode());
	}

	private void next(IxFlow f, Row row, int offset) {
		if (f == null)<commit_msg>write sheet headers in Excel export<commit_after>package org.openlca.io.xls;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.function.Consumer;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.openlca.core.database.IDatabase;
import org.openlca.core.matrix.MatrixData;
import org.openlca.core.matrix.format.ByteMatrixReader;
import org.openlca.core.matrix.format.MatrixReader;
import org.openlca.core.matrix.io.MatrixExport;
import org.openlca.core.matrix.io.index.IxContext;
import org.openlca.core.matrix.io.index.IxEnviIndex;
import org.openlca.core.matrix.io.index.IxFlow;
import org.openlca.core.matrix.io.index.IxImpact;
import org.openlca.core.matrix.io.index.IxImpactIndex;
import org.openlca.core.matrix.io.index.IxLocation;
import org.openlca.core.matrix.io.index.IxProvider;
import org.openlca.core.matrix.io.index.IxTechIndex;

public class MatrixExcelExport extends MatrixExport {

	private boolean skipZeros = true;

	public MatrixExcelExport(IDatabase db, File folder, MatrixData data) {
		super(db, folder, data);
	}

	public MatrixExcelExport skipZeros(boolean b) {
		this.skipZeros = b;
		return this;
	}

	@Override
	protected void write(MatrixReader matrix, String name) {
		if (matrix == null || name == null)
			return;
		sheetOf(name, sheet -> {
			for (int i = 0; i < matrix.rows(); i++) {
				var row = sheet.createRow(i);
				for (int j = 0; j < matrix.columns(); j++) {
					double val = matrix.get(i, j);
					if (skipZeros && val == 0)
						continue;
					row.createCell(j).setCellValue(val);
				}
			}
		});
	}

	@Override
	protected void write(double[] vector, String name) {
		if (vector == null || name == null)
			return;
		sheetOf(name, sheet -> {
			for (int i = 0; i < vector.length; i++) {
				sheet.createRow(i)
					.createCell(0)
					.setCellValue(vector[i]);
			}
		});
	}

	@Override
	protected void write(ByteMatrixReader matrix, String name) {
		if (matrix == null || name == null)
			return;
		sheetOf(name, sheet -> {
			for (int i = 0; i < matrix.rows(); i++) {
				var row = sheet.createRow(i);
				for (int j = 0; j < matrix.columns(); j++) {
					byte val = matrix.get(i, j);
					if (skipZeros && val == 0)
						continue;
					row.createCell(j).setCellValue(val);
				}
			}
		});
	}

	@Override
	public void writeIndices() {

		var context = IxContext.of(db);

		// tech. index
		if (data.techIndex != null) {
			var techIdx = IxTechIndex.of(data.techIndex, context);
			sheetOf("index_A", sheet -> {
				header(sheet,
					"Index",
					"Process ID",
					"Process name",
					"Process category",
					"Process location",
					"Flow ID",
					"Flow name",
					"Flow category",
					"Flow unit",
					"Flow type");
				var i = 0;
				for (var item : techIdx.items()) {
					i++;
					var row = sheet.createRow(i);
					Excel.cell(row, 0, item.index());
					next(item.provider(), row);
					next(item.flow(), row, 5);
				}
			});
		}

		// flow index
		if (data.enviIndex != null) {
			var enviIdx = IxEnviIndex.of(data.enviIndex, context);
			sheetOf("index_B", sheet -> {
				header(sheet,
					"Index",
					"Flow ID",
					"Flow name",
					"Flow category",
					"Flow unit",
					"Flow type",
					"Location ID",
					"Location name",
					"Location code");
				int i = 0;
				for (var item : enviIdx.items()) {
					i++;
					var row = sheet.createRow(i);
					Excel.cell(row, 0, item.index());
					next(item.flow(), row, 1);
					next(item.location(), row);
				}
			});
		}

		// impact index
		if (data.impactIndex != null) {
			var impactIdx = IxImpactIndex.of(data.impactIndex);
			sheetOf("index_C", sheet -> {
				header(sheet,
					"Index",
					"Indicator ID",
					"Indicator name",
					"Indicator unit");
				int i = 0;
				for (var item : impactIdx.items()) {
					i++;
					var row = sheet.createRow(i);
					Excel.cell(row, 0, item.index());
					next(item.impact(), row);
				}
			});
		}
	}

	private void sheetOf(String name, Consumer<Sheet> fn) {
		try (var wb = new SXSSFWorkbook(-1)) {
			var sheet = wb.createSheet(name);
			fn.accept(sheet);
			var file = new File(folder, name + ".xlsx");
			try (var stream = new FileOutputStream(file)) {
				wb.write(stream);
				wb.dispose();
			}
		} catch (IOException e) {
			throw new RuntimeException(
				"failed to write matrix " + name, e);
		}
	}

	private void header(Sheet sheet, String... h) {
		var row = sheet.createRow(0);
		for (int i = 0; i < h.length; i++) {
			Excel.cell(row, i, h[i]);
		}
	}

	private void next(IxProvider p, Row row) {
		if (p == null)
			return;
		Excel.cell(row, 1, p.id());
		Excel.cell(row, 2, p.name());
		Excel.cell(row, 3, p.category());
		Excel.cell(row, 4, p.locationCode());
	}

	private void next(IxFlow f, Row row, int offset) {
		if (f == null)
{'fraction_non_alphanumeric': 0.15922032413491022, 'fraction_numerical': 0.004818221638195357, 'mean_word_length': 3.077232142857143, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 17, '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': '3401793', 'n_tokens_mistral': 3946, 'n_tokens_neox': 3274, 'n_words': 763}