/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2020,2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.*
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html
 *    mailing list: http://www.repo.hu/projects/sch-rnd/contact.html
 */


#ifndef CSCH_OPERATIONS_H
#define CSCH_OPERATIONS_H

#include "concrete.h"

typedef struct csch_undo_remove_s {
	csch_chdr_t *obj;
	csch_cgrp_t *parent;
	csch_sheet_t *sheet;
	unsigned side_effects:1; /* whether side effects should be performed */
} csch_undo_remove_t;

typedef struct csch_undo_remove_s csch_undo_create_t;

typedef struct {
	csch_chdr_t *(*create)(csch_sheet_t *sheet, csch_cgrp_t *parent);
	void (*remove_alloc)(csch_undo_remove_t *slot);
	void (*remove_redo)(csch_undo_remove_t *slot);
	void (*remove_undo)(csch_undo_remove_t *slot);
	int (*isc_with_box)(csch_chdr_t *obj, csch_rtree_box_t *box);
	void (*move)(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t dx, csch_coord_t dy, int undoable);
	void (*copy)(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t dx, csch_coord_t dy, int undoable);
	void (*rotate)(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t rcx, csch_coord_t rcy, double da, int undoable);
	void (*rotate90)(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t rcx, csch_coord_t rcy, int n, int undoable);
	void (*mirror)(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t mcx, csch_coord_t mcy, int mirx, int miry, int undoable);
	void (*inst2spec)(csch_sheet_t *sheet, csch_chdr_t *obj, const csch_chdr_t *in, int undoable);
} csch_ops_t;


csch_chdr_t *csch_op_create(csch_sheet_t *sheet, csch_cgrp_t *parent, csch_ctype_t type);
csch_chdr_t *csch_op_remove(csch_sheet_t *sheet, csch_chdr_t *obj);

/* non-undoable object remove (e.g. for buffer) */
csch_chdr_t *csch_cnc_remove(csch_sheet_t *sheet, csch_chdr_t *obj);


/* migrate all objects from src to dst, leaving src empty (always undoable);
   the remember variant appends all new object pointers to dst_news */
void csch_op_merge_into(csch_sheet_t *sheet, csch_cgrp_t *dst, csch_cgrp_t *src);
void csch_op_merge_into_remember(csch_sheet_t *sheet, csch_cgrp_t *dst, csch_cgrp_t *src, vtp0_t *dst_news);

int csch_isc_with_box(csch_chdr_t *obj, csch_rtree_box_t *box);

/* Undoably move/copy object by dx;dy; the original spec is moved/copied */
void csch_move(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t dx, csch_coord_t dy, int undoable);
void csch_copy(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t dx, csch_coord_t dy, int undoable);

/* Copy inst (current final transformation) of inst_from to spec of obj; this
   can be used in a transformed group breakup to get all ex-member objects stay in place. */
void csch_inst2spec(csch_sheet_t *sheet, csch_chdr_t *obj, const csch_chdr_t *inst_from, int undoable);

/* Undoably rotate object by da degrees around rcx;rcy; the original spec is moved */
void csch_rotate(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t rcx, csch_coord_t rcy, double da, int undoable);

/* Same as rotate but works in n*90 degree angles and guarantees to avoid
   rounding errors */
void csch_rotate90(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t rcx, csch_coord_t rcy, int n, int undoable);

/* Mirror object's x or y coords (mirx or miry) around mcx;mcy */
void csch_mirror(csch_sheet_t *sheet, csch_chdr_t *obj, csch_coord_t mcx, csch_coord_t mcy, int mirx, int miry, int undoable);

/* Copy or move src into the dst group; always undoable */
csch_chdr_t *csch_op_copy_into(csch_sheet_t *sheet, csch_cgrp_t *dst, csch_chdr_t *src);
csch_chdr_t *csch_op_move_into(csch_sheet_t *sheet, csch_cgrp_t *dst, csch_chdr_t *src, int restore_conns, int undoable_conns);


const csch_ops_t *csch_op_get(csch_ctype_t type);

#endif
