//
//  bt_l2cap_cb_channel.c
//
//  Bluetooth Protocol Stack - Logical channel management control block operation
//  Copyright (C) 2013-2017 Toyohiko Togashi tog001@nifty.com
//
//
//  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.
//
//  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 <http://www.gnu.org/licenses/>
//
//
//  Update history
//  ---------- ----- -------------------------------------------
//  2013.01.21 v0.0  First cording
//  2013.04.21 v0.1  Commit
//  2013.05.08 v0.1  Code reduction, used a malloc()
//  2015.02.03 v0.3  Supported the PIC32
//  2016.02.20 v0.3c+ Bug fix, bt_l2capChannelGetNext()
//  2017.01.03 v0.3e Added a API (bt_l2capChannelFindByLink,bt_l2capChannelAddByLink)
//  2017.01.08 v0.3e Renamed scid,dcid -> peerCid,myCid
//
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "bt_l2cap_cb_channel.h"
#include "bt_l2cap_cb_link.h"

//
//    Static area
//
struct bt_l2capChannel *bt_l2capChannelRoot = NULL;

//
//    Sequential access
//
struct bt_l2capChannel *bt_l2capChannelGetNext(struct bt_l2capChannel **id) {
    struct bt_l2capChannel *p;

#ifdef UPD20160220                      // DEL START 2016.02.20
    if (*id == NULL) {
        p = bt_l2capChannelRoot;
    } else {
        p = (*id)->next;
    }
#else                                   // DEL END ADD START 2016.02.20
    p = bt_l2capChannelRoot;
    if ((id != NULL) && (*id != NULL)) {
        for(; p != NULL; p = p->next) {
            if (p == *id) {
                p = (*id)->next;
                break;
            }
        }
    }
#endif                                  // ADD END 2016.02.20
    *id = p;
    return(p);
}

//
// Search entry
//
struct bt_l2capChannel *bt_l2capChannelFind(unsigned short handle, unsigned short peerCid, unsigned short myCid) {
    struct bt_l2capChannel  *p;
    struct bt_l2capLink     *q;

    q = bt_l2capLinkFind(NULL, handle);
    for(p = bt_l2capChannelRoot; p != NULL; p = p->next) {
        if ((handle != 0) && (p->link != q)) {
            continue;
        }
        if ((peerCid != 0) && (peerCid != p->peerCid)) {
            continue;
        }
        if ((myCid != 0) && (myCid != p->myCid)) {
            continue;
        }
        break;
    }
    return(p);
}
                                        // ADD START 2017.01.03
struct bt_l2capChannel *bt_l2capChannelFindByLink(struct bt_l2capLink *link, unsigned short peerCid, unsigned short myCid) {
    struct bt_l2capChannel  *p;

    for(p = bt_l2capChannelRoot; p != NULL; p = p->next) {
        if ((link != NULL) && (p->link != link)) {
            continue;
        }
        if ((peerCid != 0) && (peerCid != p->peerCid)) {
            continue;
        }
        if ((myCid != 0) && (myCid != p->myCid)) {
            continue;
        }
        break;
    }
    return(p);
}
                                        // ADD END 2017.01.03

//
// Add entry
//
struct bt_l2capChannel *bt_l2capChannelAdd(unsigned short handle, unsigned short peerCid, unsigned short myCid){
    struct bt_l2capChannel *p;

    p = bt_l2capChannelFind(handle, peerCid, myCid);
    if (p == NULL) {
        if ((p = calloc(1, sizeof(struct bt_l2capChannel))) != NULL) {
            p->link    = bt_l2capLinkFind(NULL, handle);
            p->peerCid = peerCid;
            p->myCid   = myCid;
            p->next    = bt_l2capChannelRoot;
            bt_l2capChannelRoot = p;
        }
    }
    return(p);
}
                                        // ADD START 2017.01.03
struct bt_l2capChannel *bt_l2capChannelAddByLink(struct bt_l2capLink *link, unsigned short peerCid, unsigned short myCid){
    struct bt_l2capChannel *p;

    p = bt_l2capChannelFindByLink(link, peerCid, myCid);
    if (p == NULL) {
        if ((p = calloc(1, sizeof(struct bt_l2capChannel))) != NULL) {
            p->link    = link;
            p->peerCid = peerCid;
            p->myCid   = myCid;
            p->next    = bt_l2capChannelRoot;
            bt_l2capChannelRoot = p;
        }
    }
    return(p);
}
                                        // ADD END 2017.01.03

//
// Delete entry
//
void bt_l2capChannelDelete(struct bt_l2capChannel *entry){
    struct bt_l2capChannel *p;
    struct bt_l2capChannel *z;

    z = NULL;
    for(p = bt_l2capChannelRoot; p != NULL; p = p->next) {
        if (p == entry) {
            if (z == NULL) {
                bt_l2capChannelRoot = p->next;
            } else {
                z->next = p->next;
            }
            free(p);
            break;
        }
        z = p;
    }
    return;
}
                                        // ADD START 2015.02.03
//
// Delete all entry
//
void bt_l2capChannelClear(void) {
    struct bt_l2capChannel  *p;
    struct bt_l2capChannel  *i;

    i = NULL;
    while((p = bt_l2capChannelGetNext(&i)) != NULL) {
        bt_l2capChannelDelete(p);
    }
    return;
}
                                        // ADD END 2015.02.03
