/*
 * Copyright (c) 2010-2022 Belledonne Communications SARL.
 *
 * This file is part of Liblinphone
 * (see https://gitlab.linphone.org/BC/public/liblinphone).
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include "sal/sal.h"
#include "sal_impl.h"

SalReason _sal_reason_from_sip_code(int code) {
	if (code >= 100 && code < 300) return SalReasonNone;

	switch (code) {
		case 0:
			return SalReasonIOError;
		case 301:
			return SalReasonMovedPermanently;
		case 302:
			return SalReasonRedirect;
		case 401:
		case 407:
			return SalReasonUnauthorized;
		case 403:
			return SalReasonForbidden;
		case 404:
			return SalReasonNotFound;
		case 408:
			return SalReasonRequestTimeout;
		case 410:
			return SalReasonGone;
		case 412:
			return SalReasonConditionalRequestFailed;
		case 415:
			return SalReasonUnsupportedContent;
		case 422:
			return SalReasonSessionIntervalTooSmall;
		case 480:
			return SalReasonTemporarilyUnavailable;
		case 481:
			return SalReasonNoMatch;
		case 484:
			return SalReasonAddressIncomplete;
		case 486:
			return SalReasonBusy;
		case 487:
			return SalReasonNone;
		case 488:
			return SalReasonNotAcceptable;
		case 489:
			return SalReasonBadEvent;
		case 491:
			return SalReasonRequestPending;
		case 500:
			return SalReasonInternalError;
		case 501:
			return SalReasonNotImplemented;
		case 502:
			return SalReasonBadGateway;
		case 503:
			return SalReasonServiceUnavailable;
		case 504:
			return SalReasonServerTimeout;
		case 600:
			return SalReasonDoNotDisturb;
		case 603:
			return SalReasonDeclined;
		default:
			return SalReasonUnknown;
	}
	return SalReasonUnknown;
}

const SalErrorInfo *sal_error_info_none(void) {
	static const SalErrorInfo none = {SalReasonNone, (char *)"Ok", 200, NULL, NULL};
	return &none;
}

void sal_error_info_reset(SalErrorInfo *ei) {
	if (ei->status_string) {
		ms_free(ei->status_string);
		ei->status_string = NULL;
	}
	if (ei->warnings) {
		ms_free(ei->warnings);
		ei->warnings = NULL;
	}
	if (ei->full_string) {
		ms_free(ei->full_string);
		ei->full_string = NULL;
	}
	if (ei->protocol) {
		ms_free(ei->protocol);
		ei->protocol = NULL;
	}
	ei->protocol_code = 0;
	ei->reason = SalReasonNone;
	ei->sub_sei = NULL;
}

void sal_error_info_set(SalErrorInfo *ei,
                        SalReason reason,
                        const char *protocol,
                        int code,
                        const char *status_string,
                        const char *warning) {
	sal_error_info_reset(ei);
	if (reason == SalReasonUnknown && strcmp(protocol, "SIP") == 0 && code != 0)
		ei->reason = _sal_reason_from_sip_code(code);
	else {
		ei->reason = reason;
		if (code == 0) {
			code = LinphonePrivate::toSipCode(reason);
		}
	}
	ei->protocol_code = code;
	ei->status_string = status_string ? ms_strdup(status_string) : NULL;
	ei->warnings = warning ? ms_strdup(warning) : NULL;
	ei->protocol = protocol ? ms_strdup(protocol) : NULL;
	if (ei->status_string) {
		if (ei->warnings) ei->full_string = ms_strdup_printf("%s %s", ei->status_string, ei->warnings);
		else ei->full_string = ms_strdup(ei->status_string);
	}
}
