;;; -*-  Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;     The data in this file contains enhancments.                    ;;;;;
;;;                                                                    ;;;;;
;;;  Copyright (c) 1984,1987 by William Schelter,University of Texas   ;;;;;
;;;     All rights reserved                                            ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;     (c) Copyright 1981 Massachusetts Institute of Technology         ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package :maxima)

(macsyma-module nforma)

(declare-top (special 1//2 -1//2 displayp aliaslist in-p))

(defmvar $powerdisp nil)
(defmvar $pfeformat nil)
(defmvar $%edispflag nil)
(defmvar $exptdispflag t)
(defmvar $sqrtdispflag t)
(defmvar $negsumdispflag t)

(setq in-p nil)

(defmfun nformat (form)
  (cond ((atom form)
	 (cond ((and (realp form) (minusp form)) (list '(mminus) (- form)))
	       ((eq t form) (if in-p t '$true))
	       ((eq nil form) (if in-p nil '$false))
	       ((and displayp (car (rassoc form aliaslist :test #'eq))))
	       ;;	       (($EXTENDP FORM)
	       ;;		(NFORMAT (transform-extends form)))
	       (t form)))
	((atom (car form))
	 form)
	((eq 'rat (caar form))
	 (cond ((minusp (cadr form))
		(list '(mminus) (list '(rat) (- (cadr form)) (caddr form))))
	       (t (cons '(rat) (cdr form)))))
	((eq 'mmacroexpanded (caar form)) (nformat (caddr form)))
	((null (cdar form)) form)
	((eq 'mplus (caar form)) (form-mplus form))
	((eq 'mtimes (caar form)) (form-mtimes form))
	((eq 'mexpt (caar form)) (form-mexpt form))
	((eq 'mrat (caar form)) (form-mrat form))
	((eq 'mpois (caar form)) (nformat ($outofpois form)))
	((eq 'bigfloat (caar form))
	 (if (minusp (cadr form))
	     (list '(mminus) (list (car form) (- (cadr form)) (caddr form)))
	     (cons (car form) (cdr form))))
	(t form)))

(defun form-mplus (form &aux args trunc)
  (setq args (mapcar #'nformat (cdr form)))
  (setq trunc (member 'trunc (cdar form) :test #'eq))
  (cons (if trunc '(mplus trunc) '(mplus))
	(cond ((and (member 'ratsimp (cdar form) :test #'eq)
		    (not (member 'simp (cdar form) :test #'eq)))
	       (if $powerdisp (nreverse args) args))
	      ((and trunc (not (member 'simp (cdar form) :test #'eq))) (nreverse args))
	      ((or $powerdisp trunc (member 'cf (cdar form) :test #'eq)) args)
	      ((and $negsumdispflag (null (cdddr form)))
	       (if (and (not (mmminusp (car args)))
			(mmminusp (cadr args)))
		   args
		   (nreverse args)))
	      (t (nreverse args)))))

(defun form-mtimes (form)
  (cond ((null (cdr form)) '((mtimes)))
	((equal -1 (cadr form)) (list '(mminus) (form-mtimes (cdr form))))
        (t (prog (num den minus flag)
	      (do ((l (cdr form) (cdr l)) (dummy)) ((null l))
		(setq dummy (nformat (car l)))
		(cond ((atom dummy) (setq num (cons dummy num)))
		      ((eq 'mminus (caar dummy))
		       (setq minus (not minus) l (append dummy (cdr l))))
		      ((or (eq 'mquotient (caar dummy))
			   (and (not $pfeformat) (eq 'rat (caar dummy))))
		       (cond ((not (equal 1 (cadr dummy)))
			      (setq num (cons (cadr dummy) num))))
		       (setq den (cons (caddr dummy) den)))
		      (t (setq num (cons dummy num)))))
	      (setq num (cond ((null num) 1)
			      ((null (cdr num)) (car num))
			      (t (cons '(mtimes) (nreverse num))))
		    den (cond ((null den) (setq flag t) nil)
			      ((null (cdr den)) (car den))
			      (t (cons '(mtimes) (nreverse den)))))
	      (if (not flag) (setq num (list '(mquotient) num den)))
	      (return (if minus (list '(mminus) num) num))))))

(defun form-mexpt (form &aux exp)
  (cond ((and $sqrtdispflag (alike1 1//2 (caddr form))) (list '(%sqrt) (cadr form)))
	((and $sqrtdispflag (alike1 -1//2 (caddr form)))
	 (list '(mquotient) 1 (list '(%sqrt) (cadr form))))
	((and (or (and $%edispflag (eq '$%e (cadr form)))
		  (and $exptdispflag (not (eq '$%e (cadr form)))))
	      (not (atom (setq exp (nformat (caddr form)))))
	      (eq 'mminus (caar exp)))
	 (list '(mquotient) 1 (if (equal 1 (cadr exp)) (cadr form)
				  (list '(mexpt) (cadr form) (cadr exp)))))
	(t (cons '(mexpt) (cdr form)))))

(defun form-mrat (form)
  (let ((trunc (member 'trunc (cdar form) :test #'eq)) exact)
    (if (and trunc (eq (cadr form) 'ps))
	(setq exact (null (car (cadddr form)))))
    (setq form (ratdisrepd form))
    (rdis1 form)
    (if (and trunc (or (atom form)
		       ;; A constant, e.g. ((mplus) $a 1)
		       (not (member (car form) '((mplus exact) (mplus trunc)) :test #'equal))))
	(cons (if exact '(mplus exact) '(mplus trunc)) (ncons form))
	(nformat form))))

(defun rdis1 (form)
  (cond ((or (atom form) (specrepp form)))
	((null (cdar form)) (rplaca form (list (caar form) 'ratsimp)))
	(t (mapc #'rdis1 (cdr form)))))

;;(DEFMFUN NFORMAT-ALL (FORM)
;;  (SETQ FORM (NFORMAT FORM))
;;  (IF (OR (ATOM FORM) (EQ (CAAR FORM) 'BIGFLOAT))
;;      FORM
;;      (CONS (DELSIMP (CAR FORM)) (MAPCAR #'NFORMAT-ALL (CDR FORM)))))
;;Update from F302
(defmfun nformat-all (form)
  (setq form (nformat form))
  (if (or (atom form) (eq (caar form) 'bigfloat))
      form
      (cons (delsimp (car form))
	    (if (member (caar form) '(mdo mdoin) :test #'eq)
		(mapcar #'(lambda (u) (if u (nformat-all u))) (cdr form))
		(mapcar #'nformat-all (cdr form))))))
