/* $Revision: 1.1 $ */
/*
 *  dsp_dlyerr_sim.c - Simulation input/delay validation functions for DSP Blockset delay blocks.
 *
 *  Copyright 2000 The MathWorks, Inc.
 */

#include "dsp_dlyerr_sim.h"

#if !defined(MATLAB_MEX_FILE)
#   error "dsp_dlyerr_sim.c should not be used for S-Functions without a corresponding TLC file."
#endif


void delayValidator(SimStruct      *S, 
                    const int_T    *InputDims,
                    const int_T    *DelayDims,
                    const int_T     inputWidth,
                    const int_T     delayWidth,
                    const boolean_T isFrame,
                    const boolean_T isVariableDelay)
{
    enum {INPORT, DELAYPORT};

    if (isVariableDelay) {
        /* Block is a variable delay block, which means that
         * block has two input ports - one for the input signal
         * and one for the delay element(s)
         */
        /* Scalar delay inputs oriented or not are always fine.  They work for all data inputs */
        if (!isInputScalar(S,DELAYPORT)) {
            /* Delay is non-scalar */
            if (isInputScalar(S,INPORT)) {
                /* ERROR: Input is a scalar, but delay is not. */
                THROW_ERROR(S, "Delay must be a scalar when input is a scalar.");
            } else {
                /* Input is non-scalar */
                if (!isFrame) {
                    /* Sample-based mode
                     * - Scalar input -> Delay must be scalar
                     * - 1-D input    -> Delay can be scalar, 1-D, row vector or col vector
                     * - Row input    -> Delay can be scalar, 1-D, row vector or col vector
                     * - Col input    -> Delay can be scalar, 1-D, row vector or col vector
                     * - M-by-N input -> Delay can be scalar or M-by-N matrix only
                     */
                    if (!isInputFullMatrix(S,INPORT)) {
                        /* Input is some variety of vector, error out if delay is a matrix. */
                        if (isInputFullMatrix(S,DELAYPORT)) {
                            THROW_ERROR(S, "Delay cannot be a matrix when input is a vector.");
                        } else {
                            /* Delay is some variety of vector as well, check lengths. */
                            if (delayWidth != inputWidth) {
                                THROW_ERROR(S, "Delay vector must be the same length as the input vector.");
                            }
                        }
                    } else {
                        /* Input is an M-by-N matrix, delay must be scalar or an M-by-N matrix. */
                        if (!isInputFullMatrix(S,DELAYPORT) || 
                            ((DelayDims[0] != InputDims[0]) || (DelayDims[1] != InputDims[1])) ) {
                            THROW_ERROR(S, "Delay must be a scalar or an M-by-N matrix when input is a sample-based M-by-N matrix.");
                        }
                    }
                } else {
                    /* Frame-based mode
                     * - Scalar input -> Delay must be scalar
                     * - 1-D input    -> "Inconceivable!"
                     * - Row input    -> Delay must be scalar, 1-D, or row vector
                     * - Col input    -> Delay must be scalar, 1-D, or col vector
                     * - M-by-N input -> Delay must be scalar, row (N), col (M), or M-by-N
                     */
                    if (!isInputFullMatrix(S,INPORT)) {
                        /* Input is a frame-based row or column vector */
                        if (isInputFullMatrix(S,DELAYPORT)) {
                            /* Delay is a matrix - gasp! */
                            THROW_ERROR(S, "Delay cannot be a matrix when input is a vector.");
                        } else {
                            /* Delay is a vector - make sure orientations match */
                            if ((isInputRowVector(S, INPORT) && isInputColVector(S, DELAYPORT)) ||
                                (isInputColVector(S, INPORT) && isInputRowVector(S, DELAYPORT)) ) {
                                THROW_ERROR(S, "Delay vector must be 1-D or the same orientation as the frame-based input vector.");
                            } else if (delayWidth != inputWidth) {
                                        THROW_ERROR(S, "Delay vector must have the same number of elements "
                                                       "as the frame-based input vector." );
                            }
                        }
                    } else {
                        /* Input is a frame-based M-by-N matrix */
                        if (isInputUnoriented(S,DELAYPORT)) {
                            /* ERROR: Delay is a 1-D vector */
                            THROW_ERROR(S, "Delay cannot be an unoriented vector when input is a frame-based matrix.");
                        } else if (isInputRowVector(S,DELAYPORT)) {
                            /* Delay is a row vector: length must equal number of input columns */
                            if (delayWidth != InputDims[1]) {
                                THROW_ERROR(S, "Row vector delay must be of length N for an M-by-N frame-based input matrix.");
                            }
                        } else if (isInputColVector(S,DELAYPORT)) {
                            /* Delay is a column vector: length must equal number of input rows */
                            if (delayWidth != InputDims[0]) {
                                THROW_ERROR(S, "Column vector delay must be of length M for M-by-N frame-based input matrix.");
                            }
                        } else {
                            /* Delay is a matrix: dimensions must match that of M-by-N input */
                            if ((DelayDims[0] != InputDims[0]) || (DelayDims[1] != InputDims[1])) {
                                THROW_ERROR(S, "Matrix delay must be an M-by-N matrix for an M-by-N frame-based input matrix.");
                            }
                        }
                    }
                }
            }
        }
    } else {
        /* Block is *not* a variable delay block, which means that
         * the delay is specified via an edit box in the mask
         * dialog box.
         */
        /* Scalar delay inputs are always fine.  They work for all data inputs */
        if (delayWidth > 1) {
            if (isInputScalar(S,INPORT)) {
                THROW_ERROR(S, "Delay must be a scalar when input is a scalar.");
            }

            if (isInputUnoriented(S,INPORT)) {
                /* We'll allow (for user convenience) a row or column vector of delays
                 * with an unoriented data input as long as the number of elements match.
                 */
                if ( (inputWidth != delayWidth) ||
                     ((DelayDims[0] > 1) && (DelayDims[1] > 1))
                   ) {
                    THROW_ERROR(S, "For length-M 1-D inputs, the delay must be a scalar or a length-M vector.");
                }

            } else {
                /* Oriented (2-D) input signal: */
                boolean_T isDelayRowVector = (boolean_T)((DelayDims[0] == 1) && (DelayDims[1] >  1));
                boolean_T isDelayColVector = (boolean_T)((DelayDims[0] >  1) && (DelayDims[1] == 1));
                boolean_T isDelayMatrix    = (boolean_T)((DelayDims[0] >  1) && (DelayDims[1] >  1));
    
                if (!isFrame) {
                    /* Sample-based mode:
                     * Scalar input and 1-D input cases have been handled above
                     * 1-x-N input -> Delay can be scalar, 1-x-N, or N-x-1
                     * M-x-1 input -> Delay can be scalar, 1-x-M, or M-x-1
                     * M-x-N input -> Delay can be scalar or M-x-N only.
                     */
                    if (isInputRowVector(S,INPORT) || isInputColVector(S,INPORT)) {
                        if (isDelayMatrix) {
                            THROW_ERROR(S, "Delay cannot be a matrix when input is a vector.");
                        } else if (delayWidth != inputWidth) {
                            THROW_ERROR(S, "Delay vector must have the same number of elements as the input vector.");
                        }
                    } else { /* Input is an M-x-N sample-based matrix */
                        if (!isDelayMatrix ||
                            ((DelayDims[0] != InputDims[0]) || (DelayDims[1] != InputDims[1]))
                            ) {
                            THROW_ERROR(S, "Delay must be a scalar or an M-by-N matrix when input is a sample-based M-by-N matrix.");
                        }
                    }

                } else {
                    /* Frame-based mode:
                     * Scalar input case has been handled above
                     * 1-x-N input -> Delay can be scalar or 1-x-N
                     * M-x-1 input -> Delay can be scalar or M-x-1
                     * M-x-N input -> Delay can be scalar or 1-x-N or M-x-1 or M-x-N
                     */
                    const int_T rowsMatch = (DelayDims[0] == InputDims[0]);
                    const int_T colsMatch = (DelayDims[1] == InputDims[1]);

                    if (isInputFullMatrix(S,INPORT)) {
                        if (isDelayRowVector && !colsMatch) {
                            THROW_ERROR(S, "Row vector delay must be of length N for an M-by-N frame-based input matrix.");
                        } else if (isDelayColVector && !rowsMatch) {
                            THROW_ERROR(S, "Column vector delay must be of length M for M-by-N frame-based input matrix.");
                        } else if (isDelayMatrix && (!colsMatch || !rowsMatch)) {
                            THROW_ERROR(S, "Matrix delay must be an M-by-N matrix for an M-by-N frame-based input matrix.");
                        }

                    } else {
                        /* Input must be a vector */
                        if ((DelayDims[0] != InputDims[0]) || (DelayDims[1] != InputDims[1])) {
                            THROW_ERROR(S, "Delay parameter must be a scalar, or a vector with the "
                                           "same dimensions as the frame-based input signal.");
                        }
                    }
                }
            }
        }
    }
} /* delayValidator */

/* [EOF] dsp_dlyerr_sim.c */
