/* SPDX-FileCopyrightText: 2026 Project Tick
 * SPDX-FileContributor: Project Tick
 * SPDX-License-Identifier: GPL-3.0-or-later WITH LicenseRef-MeshMC-MMCO-Module-Exception-1.0
 *
 *   MeshMC - A Custom Launcher for Minecraft
 *   Copyright (C) 2026 Project Tick
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version, with the additional permission
 *   described in the MeshMC MMCO Module Exception 1.0.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   You should have received a copy of the MeshMC MMCO Module Exception 1.0
 *   along with this program.  If not, see <https://projecttick.org/licenses/>.
 */

#pragma once
#include "membuffer.h"
#include "constants.h"
#include "annotations.h"
#include <map>
namespace java
{
	/**
	 * Class representing a Java .class file
	 */
	class classfile : public util::membuffer
	{
	  public:
		classfile(char* data, std::size_t size) : membuffer(data, size)
		{
			valid = false;
			is_synthetic = false;
			read_be(magic);
			if (magic != 0xCAFEBABE)
				throw new classfile_exception();
			read_be(minor_version);
			read_be(major_version);
			constants.load(*this);
			read_be(access_flags);
			read_be(this_class);
			read_be(super_class);

			// Interfaces
			uint16_t iface_count = 0;
			read_be(iface_count);
			while (iface_count) {
				uint16_t iface;
				read_be(iface);
				interfaces.push_back(iface);
				iface_count--;
			}

			// Fields
			// read fields (and attributes from inside fields) (and possible
			// inner classes. yay for recursion!) for now though, we will ignore
			// all attributes
			/*
			 * field_info
			 * {
			 *     u2 access_flags;
			 *     u2 name_index;
			 *     u2 descriptor_index;
			 *     u2 attributes_count;
			 *     attribute_info attributes[attributes_count];
			 * }
			 */
			uint16_t field_count = 0;
			read_be(field_count);
			while (field_count) {
				// skip field stuff
				skip(6);
				// and skip field attributes
				uint16_t attr_count = 0;
				read_be(attr_count);
				while (attr_count) {
					skip(2);
					uint32_t attr_length = 0;
					read_be(attr_length);
					skip(attr_length);
					attr_count--;
				}
				field_count--;
			}

			// class methods
			/*
			 * method_info
			 * {
			 *     u2 access_flags;
			 *     u2 name_index;
			 *     u2 descriptor_index;
			 *     u2 attributes_count;
			 *     attribute_info attributes[attributes_count];
			 * }
			 */
			uint16_t method_count = 0;
			read_be(method_count);
			while (method_count) {
				skip(6);
				// and skip method attributes
				uint16_t attr_count = 0;
				read_be(attr_count);
				while (attr_count) {
					skip(2);
					uint32_t attr_length = 0;
					read_be(attr_length);
					skip(attr_length);
					attr_count--;
				}
				method_count--;
			}

			// class attributes
			// there are many kinds of attributes. this is just the generic
			// wrapper structure. type is decided by attribute name. extensions
			// to the standard are *possible* class annotations are one kind of
			// a attribute (one per class)
			/*
			 * attribute_info
			 * {
			 *     u2 attribute_name_index;
			 *     u4 attribute_length;
			 *     u1 info[attribute_length];
			 * }
			 */
			uint16_t class_attr_count = 0;
			read_be(class_attr_count);
			while (class_attr_count) {
				uint16_t name_idx = 0;
				read_be(name_idx);
				uint32_t attr_length = 0;
				read_be(attr_length);

				auto name = constants[name_idx];
				if (name.str_data == "RuntimeVisibleAnnotations") {
					uint16_t num_annotations = 0;
					read_be(num_annotations);
					while (num_annotations) {
						visible_class_annotations.push_back(
							annotation::read(*this, constants));
						num_annotations--;
					}
				} else
					skip(attr_length);
				class_attr_count--;
			}
			valid = true;
		};
		bool valid;
		bool is_synthetic;
		uint32_t magic;
		uint16_t minor_version;
		uint16_t major_version;
		constant_pool constants;
		uint16_t access_flags;
		uint16_t this_class;
		uint16_t super_class;
		// interfaces this class implements ? must be. investigate.
		std::vector<uint16_t> interfaces;
		// FIXME: doesn't free up memory on delete
		java::annotation_table visible_class_annotations;
	};
} // namespace java