from __future__ import print_function
from six import iteritems
import numpy as np
from pyNastran.bdf.cards.elements.shell import CTRIA3


def convert_bad_quads_to_tris(model, eids_to_check=None, xyz_cid0=None, min_edge_length=0.0):
    """
    A standard quad is a nice rectangle.  If an edge is collapsed, it's a triangle.
    Change the element type.

    Parameters
    ----------
    model : BDF()
        a BDF model that has not had it's properties/load xref'd, but is valid
        such that it could
    eids : list; (default=None -> all CQUAD4s)
        the subset of element ids to check
    xyz_cid0 : (n, 3) ndarray
        nodes in cid=0
    min_edge_length : float; default=0.0
        what is classified as "short"

    Warning
    -------
    Don't cross reference properties/loads

    TODO:
    -----
    check for bad xref
    """
    out = model.get_card_ids_by_card_types('CQUAD4')
    cquad4s = out['CQUAD4']
    if eids_to_check is None:
        cquad4s_to_check = cquad4s
    else:
        cquad4s_to_check = list(set(eids_to_check).intersection(set(cquad4s)))

    elements = model.elements
    eids_to_remove = []

    if xyz_cid0 is None:
        xyz_cid0 = model.get_xyz_in_coord(cid=0)
    nid_cd = np.array([[nid, node.Cd()] for nid, node in sorted(iteritems(model.nodes))])
    all_nids = nid_cd[:, 0]

    if len(cquad4s_to_check) == 0:
        model.log.warning('no quads in the model...')
        return

    for eid in sorted(cquad4s_to_check):
        elem = elements[eid]
        nids = elem.node_ids
        nids_long = nids + nids

        nids_to_remove = []
        for inode in range(4):
            nid0 = nids_long[inode]
            nid1 = nids_long[inode + 1]
            edge = [nid0, nid1]
            i = np.searchsorted(all_nids, edge)
            xyz = xyz_cid0[i, :]
            edge_length = np.linalg.norm(xyz[0, :] - xyz[1, :])
            if edge_length <= min_edge_length:
                nids_to_remove.append(nid1)

        if len(nids_to_remove) == 0:
            continue

        for nid in nids_to_remove:
            nids.remove(nid)

        if len(nids) < 3:
            model.log.debug('found eid=%s is a line/point...removing' % eid)
            etype = elem.type
            model.card_count[etype] -= 1
            del model.elements[eid]
            continue

        nids_to_remove = []
        nids_long = nids + nids
        for inode in range(3):
            nid0 = nids_long[inode]
            nid1 = nids_long[inode + 1]
            edge = [nid0, nid1]
            i = np.searchsorted(all_nids, edge)
            xyz = xyz_cid0[i, :]
            edge_length = np.linalg.norm(xyz[0, :] - xyz[1, :])
            if edge_length <= min_edge_length:
                nids_to_remove.append(nid1)

        for nid in nids_to_remove:
            nids.remove(nid)

        if len(nids) < 3:
            model.log.debug('found eid=%s is a line/point...removing' % eid)
            etype = elem.type
            model.card_count[etype] -= 1
            del model.elements[eid]
            continue

        model.log.debug('found eid=%s is a triangle...replacing CQUAD4 with CTRIA3' % eid)
        #print('  nids2=%s' % (nids))
        assert elem.TFlag == 0, elem
        assert elem.T1 is None, elem.T1
        assert elem.T2 is None, elem.T2
        assert elem.T3 is None, elem.T3
        assert elem.T4 is None, elem.T4
        elem2 = CTRIA3(eid, elem.Pid(), nids, elem.zOffset,
                       thetaMcid=elem.thetaMcid, TFlag=0, T1=None, T2=None, T3=None,
                       comment='$ was a CQUAD4\n')
        model._increase_card_count('CTRIA3')
        del model.elements[eid]
        model.elements[eid] = elem2
