%%--------------------------------------------------------------------
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
%% 
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%% 
%% %CopyrightEnd%
%%
%%
%%--------------------------------------------------------------------
%% File    : CosNotification_Common.erl
%% Purpose : 
%%--------------------------------------------------------------------

-module('CosNotification_Common').


%%--------------- INCLUDES -----------------------------------
-include_lib("orber/include/corba.hrl").
%% Application files
-include("CosNotification.hrl").
-include("CosNotifyChannelAdmin.hrl").
-include("CosNotifyComm.hrl").
-include("CosNotifyFilter.hrl").

-include("CosNotification_Definitions.hrl").

%%--------------- EXPORTS ------------------------------------
%% External MISC
-export([get_option/3, 
         create_name/0,
         create_name/1,
         create_name/2, 
	 create_id/0,
	 create_id/1,
         is_debug_compiled/0,
	 type_check/2,
         send_stubborn/5,
         create_link/3, 
	 disconnect/3, 
	 do_disconnect/3,
	 notify/1]).

%% Internal AdminProperties
-export([init_adm/1,
	 set_adm/2,
	 'MaxQueueLength'/6,
	 'MaxConsumers'/6,
	 'MaxSuppliers'/6]).
%% Internal QoS
-export([init_qos/1,
	 set_qos/5,
	 validate_qos/5,
	 validate_event_qos/2,
	 'EventReliability'/6,
	 'ConnectionReliability'/6,
	 'Priority'/6,
	 'StartTimeSupported'/6,
	 'StopTimeSupported'/6,
	 'Timeout'/6,
	 'OrderPolicy'/6,
	 'DiscardPolicy'/6,
	 'MaximumBatchSize'/6,
	 'PacingInterval'/6,
	 'MaxEventsPerConsumer'/6]).

%%--------------- DEFINITIONS OF CONSTANTS -------------------
%%--------------- EXTERNAL MISC FUNCTIONS --------------------
%%------------------------------------------------------------
%% function : create_link
%% Arguments: Module - which Module to call
%%            Env/ArgList - ordinary oe_create arguments.
%% Returns  : 
%% Exception: 
%% Effect   : Necessary since we want the supervisor to be a 
%%            'simple_one_for_one'. Otherwise, using for example,
%%            'one_for_one', we have to call supervisor:delete_child
%%            to remove the childs startspecification from the 
%%            supervisors internal state.
%%------------------------------------------------------------
create_link(Module, Env, ArgList) ->
    Module:oe_create_link(Env, ArgList).

%%-----------------------------------------------------------%
%% function : get_option
%% Arguments: 
%% Returns  : 
%% Exception: 
%% Effect   : 
%%------------------------------------------------------------
get_option(Key, OptionList, DefaultList) ->
    case lists:keysearch(Key, 1, OptionList) of
        {value,{Key,Value}} ->
            Value;
        _ ->
            case lists:keysearch(Key, 1, DefaultList) of
                {value,{Key,Value}} ->
                    Value;
                _->
                    {error, "Invalid option"}
            end
    end.

%%------------------------------------------------------------
%% function : create_name
%% Arguments: 
%% Returns  : 
%% Effect   : Create a unique name to use when, for eaxmple, starting
%%            a new server.
%%------------------------------------------------------------
create_name() ->
    Time = erlang:system_time(),
    Unique = erlang:unique_integer([positive]),
    lists:concat(['oe_',node(),'_',Time,'_',Unique]).


%%-----------------------------------------------------------%
%% function : create_name/1
%% Arguments: 
%% Returns  : 
%% Exception: 
%% Effect   : 
%%------------------------------------------------------------ 
create_name(Type) ->
    Time = erlang:system_time(),
    Unique = erlang:unique_integer([positive]),
    lists:concat(['oe_',node(),'_',Type,'_',Time,'_',Unique]).

%%-----------------------------------------------------------%
%% function : create_name/2
%% Arguments: 
%% Returns  : 
%% Exception: 
%% Effect   : 
%%------------------------------------------------------------
create_name(Name,Type) ->
    Time = erlang:system_time(),
    Unique = erlang:unique_integer([positive]),
    lists:concat(['oe_',node(),'_',Type,'_',Name,'_',Time,'_',Unique]).
 
%%------------------------------------------------------------
%% function : create_id/0
%% Arguments: - 
%% Returns  : id (long) =/= 0
%%            Both default Admin:s have the unique id 0 (OMG spec, 98-11-01, 
%%            Notification p 148), hence, we may not return 0.
%% Exception: 
%% Purpose  : Throughout the CosNotification service we use,
%%            according to the OMG specification, id:s (long),
%%            which must be "unique", to retrieve object references.
%%            For example: CosNotifyChannelAdmin::ChannelId/AdminID.
%%------------------------------------------------------------
create_id(-1) ->
    1;
create_id(2147483647) ->
    -2147483648;
create_id(OldID) ->
    OldID+1.

create_id() ->
    {_A,_B,C}=erlang:timestamp(),
    C.
 
%%------------------------------------------------------------
%% function : type_check
%% Arguments: Obj  - objectrefernce to test.
%%            Mod  - Module which contains typeID/0.
%% Returns  : 'ok' or raises exception.
%% Effect   : 
%%------------------------------------------------------------
type_check(Obj, Mod) ->
    case cosNotificationApp:type_check() of
	false ->
	    ok;
	_ ->
	    case catch corba_object:is_a(Obj,Mod:typeID()) of
		true ->
		    ok;
		false ->
		    orber:dbg("[~p] CosNotification_Common:type_check(~p);~n"
			      "The supplied Object is not or does not inherrit from: ~p", 
			      [?LINE, Obj, Mod], ?DEBUG_LEVEL),
		    corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO});
		{'EXCEPTION', E} ->
		    orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n"
			      "Failed due to: ~p", 
			      [?LINE, Obj, Mod, E], ?DEBUG_LEVEL),
		    corba:raise(E);
		What ->
		    orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n"
			      "Failed due to: ~p", 
			      [?LINE, Obj, Mod, What], ?DEBUG_LEVEL),
		    corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
	    end
    end.
	

%%-----------------------------------------------------------%
%% function : notify
%% Arguments: Items - [Item]
%%            Item - {proxy, IOR} | {client, IOR} | {reason, term()}
%% Returns  : 'ok' or raises exception.
%% Effect   : 
%%------------------------------------------------------------
notify(Items) ->
    case cosNotificationApp:notify() of
	false ->
	    ok;
	Module ->
	    catch Module:terminated(Items),
	    ok
    end.
	

%%------------------------------------------------------------
%% function : send_stubborn
%% Arguments: M - module
%%            F - function
%%            A - arguments
%%            MaxR - Maximum no retries
%%            Wait - sleep Wait seconds before next try.
%% Returns  : see effect
%% Exception: 
%% Effect   : Retries repeatidly untill anything else besides
%%            'EXIT', 'COMM_FAILURE' or 'OBJECT_NOT_EXIST'
%%------------------------------------------------------------
 
send_stubborn(M, F, A, MaxR, Wait) when is_list(A) ->
    send_stubborn(M, F, A, MaxR, Wait, 0);
send_stubborn(M, F, A, MaxR, Wait) ->
    send_stubborn(M, F, [A], MaxR, Wait, 0).
send_stubborn(M, F, A, MaxR, _Wait, MaxR) ->
    orber:dbg("[~p] CosNotification_Common:send_stubborn( ~p ~p ~p ~p).~n"
	      "Failed to deliver the event.~n", [?LINE, M,F,A,MaxR], ?DEBUG_LEVEL),
    corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO});
send_stubborn(M, F, A, MaxR, Wait, Times) ->
    ?debug_print("~p:~p(~p)  # of retries: ~p~n", [M,F,A, Times]),    
    case catch apply(M,F,A) of
        {'EXCEPTION', E} when is_record(E, 'COMM_FAILURE')->
            NewTimes = Times +1,
            timer:sleep(Wait),
            send_stubborn(M, F, A, MaxR, Wait, NewTimes);
        {'EXIT', _} ->
            NewTimes = Times +1,
            timer:sleep(Wait),
            send_stubborn(M, F, A, MaxR, Wait, NewTimes);
        Other ->
            Other
    end.


%%-----------------------------------------------------------%
%% function : disconnect
%% Arguments: Module - one of the interfaces defined in CosEventComm.
%%            Function - the appropriate disconnect function.
%%            Object - the client object reference.
%% Returns  : ok
%% Exception: 
%% Effect   : If the process would try to diconnect itself it could
%%            result in a deadlock. Hence, we spawn a new process to do it.
%%------------------------------------------------------------
disconnect(Module, Function, Object) ->
    spawn(?MODULE, do_disconnect, [Module, Function, Object]),
    ok.

do_disconnect(Module, Function, Object) ->
    catch Module:Function(Object),
    ?DBG("Disconnect ~p:~p(..).~n", [Module, Function]),
    ok.


 
%%------------------------------------------------------------
%% function : is_debug_compiled
%% Arguments: 
%% Returns  : 
%% Exception: 
%% Effect   : 
%%------------------------------------------------------------
 
-ifdef(debug).
    is_debug_compiled() -> true.
-else.
    is_debug_compiled() -> false.
-endif.
 

%%------------------------------------------------------------
%%--------------- AdminPropertiesAdmin -----------------------
%%------------------------------------------------------------
%%------------------------------------------------------------
%% function : init_adm
%% Arguments: Wanted  - requested Admins to be set.
%% Returns  : #'CosNotification_UnsupportedAdmin'{} |
%%            {NewAdmProperties, [MaxQ, MaxC, MaxS]}
%% Effect   : may only be used when creating a channel!!!!!!!!
%%------------------------------------------------------------
init_adm(Wanted) ->
    {NewA,_} = set_properties(Wanted, ?not_DEFAULT_ADMINPROPERTIES, channelAdm, 
			      ?not_SUPPORTED_ADMINPROPERTIES, [], [], 
			      false, false, false),
    {NewA, [extract_value(NewA, ?not_MaxQueueLength),
	    extract_value(NewA, ?not_MaxConsumers),
	    extract_value(NewA, ?not_MaxSuppliers)]}.

set_adm(Wanted, Current) ->
    {NewA,_} = set_properties(Wanted, Current, channelAdm, 
			      ?not_SUPPORTED_ADMINPROPERTIES, 
			      [], [], false, false, false),
    {NewA, [extract_value(NewA, ?not_MaxQueueLength),
	    extract_value(NewA, ?not_MaxConsumers),
	    extract_value(NewA, ?not_MaxSuppliers)]}.

'MaxQueueLength'(Req,channelAdm,_, _, _, _) -> admin_ok(Req).
'MaxConsumers'(Req,channelAdm,_, _, _, _)->    admin_ok(Req).
'MaxSuppliers'(Req,channelAdm,_, _, _, _)->    admin_ok(Req).

admin_ok(Req) ->
    case any:get_value(Req#'CosNotification_Property'.value) of
	Val when is_integer(Val) andalso Val >= 0 ->
	    {ok, Req};
	_  ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end.


%%------------------------------------------------------------
%%--------------- QOS FUNCTIONS ------------------------------
%%------------------------------------------------------------
%%------------------------------------------------------------
%% function : init_qos
%% Arguments: Wanted  - requested QoS to be set.
%% Returns  : see set_properties/9
%% Effect   : may only be used when creating a channel!!!!!!!!
%%------------------------------------------------------------
init_qos(Wanted) ->
    LQS = set_local_qos(?not_DEFAULT_QOS, ?not_CreateInitQoS()),
    set_properties(Wanted, ?not_DEFAULT_QOS, channel, ?not_SUPPORTED_QOS, 
		   [], [], false, [], LQS).

%%------------------------------------------------------------
%% function : set_qos/5
%% Arguments: Wanted  - requested QoS to be set.
%%            Current - current QoS OMG style
%%            LQS     - local representation of QoS.
%%            Type    - channel | admin | proxy
%%            Parent  - Factory if Channel, Channel if Admin etc
%%            Childs  - Admins if Channel etc
%% Returns  : see set_properties/9
%%------------------------------------------------------------
set_qos(Wanted, {Current, LQS}, proxy, Parent, _) ->
    set_properties(Wanted, Current, proxy, ?not_SUPPORTED_QOS, [], [], Parent, false,LQS);
set_qos(Wanted, {Current, LQS}, admin, Parent, Childs) ->
    set_properties(Wanted, Current, admin, ?not_SUPPORTED_QOS, [], [], Parent, Childs,LQS);
set_qos(Wanted, {Current, LQS}, channel, _, Childs) ->
    set_properties(Wanted, Current, channel, ?not_SUPPORTED_QOS, [], [], false, Childs,LQS).

%%------------------------------------------------------------
%% function : 
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : ok - if requested equal to current value.
%%            {ok, Req, LQS} - if new and allowed QoS
%%            {unsupported,#'CosNotification_PropertyError'{}} otherwise.
%% Effect   : 
%%------------------------------------------------------------
'EventReliability'(Req,channel, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
	{Val, Val, _, _} ->
	    %% Is the value requested.
	    ok;
	{Val, _, Val, _} ->
	    {ok, Req, LQS};
	{Val, _, _, Val} ->
	    {ok, Req, LQS};
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end;
'EventReliability'(Req,_,_,_,_,_) ->
    %% only valid to set this QoS for channels (or per-event).
    {unsupported, 
     #'CosNotification_PropertyError'{
       code = 'UNAVAILABLE_PROPERTY', 
       name = Req#'CosNotification_Property'.name,
       available_range = #'CosNotification_PropertyRange'{
	 low_val=any:create(orber_tc:null(), null), 
	 high_val=any:create(orber_tc:null(), null)
	}
      }
    }.

%%------------------------------------------------------------
%% function : 'ConnectionReliability'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Exception: 
%% Effect   : 
%%------------------------------------------------------------
%% The most complex QoS to set is ConnectionReliability, and the reason for this
%% is that we cannot set the Channel to offer best effort while its children
%% offer persistent. A child may only offer Persistent if its parent do, which
%% is why we must check the following:
%%           
%%                    #    Persistent        Change to       Best Effort
%%            _____
%%           |     | (1)                         ->       Check if children BE
%%           |Chann| (2)      ok                 <-
%%            -----
%%              |
%%            _____
%%           |     | (3)                         ->      Check if children BE
%%           |Admin| (4)  Check if parent Pers.  <-      
%%            -----
%%              |
%%            _____
%%           |     | (5)                         ->               ok
%%           |Proxy| (6) Check if parent Pers.   <-
%%            -----
%% NOTE: a parent always exists but we may change the QoS before creating any
%% childrens. The cases (2) and (5) is always ok, i.e., no need to confirm
%% with parent or children.
%%------------------------------------------------------------
'ConnectionReliability'(Req, channel, _Curr, _Parent, Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
	{Val, Val, _, _} ->
	    %% Is the value requested.
	    ok;
	{Val, P, Val, P} ->
	    %% Requested is BestEffort, Current Persistent => (1)
	    check_with_relatives(Childs, Req, LQS);
	{Val, B, B, Val} ->
	    %% Requested is Persistent, Current BestEffort => (2)
	    {ok, Req, LQS};
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end;
'ConnectionReliability'(Req, admin, _Curr, Parent, Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
	{Val, Val, _, _} ->
	    %% Is the value requested.
	    ok;
	{Val, P, Val, P} ->
	    %% Requested is BestEffort, Current Persistent => (3)
	    check_with_relatives(Childs, Req, LQS);
	{Val, B, B, Val} ->
	    %% Requested is Persistent, Current BestEffort => (4)
	    check_with_relatives([Parent], Req, LQS);
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end;
'ConnectionReliability'(Req, proxy, _Curr, Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of
	{Val, Val, _, _} ->
	    %% Is the value requested.
	    ok;
	{Val, P, Val, P} ->
	    %% Requested is BestEffort, Current Persistent => (5)
	    {ok, Req, LQS};
	{Val, B, B, Val} ->
	    %% Requested is Persistent, Current BestEffort => (6)
	    check_with_relatives([Parent], Req, LQS);
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end.

%%------------------------------------------------------------
%% function : 'Priority'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'Priority'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetPriority(LQS), ?not_HighestPriority, ?not_LowestPriority} of
	{Val, Val, _, _} ->
	    ok;
	{Val, _, H, L} when Val =< H, Val >= L ->
	    {ok, Req, LQS};
	{_, _, H, L} ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:short(), L), 
		 high_val=any:create(orber_tc:short(), H)
		}
	      }
	    }
    end.

%%------------------------------------------------------------
%% function : 'StartTimeSupported'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'StartTimeSupported'(Req, _Type, _Curr, _, _, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetStartTimeSupported(LQS)} of
	{Val, Val} ->
	    ok;
	{Val, _} when Val =/= true, Val =/= false ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:boolean(), false), 
		 high_val=any:create(orber_tc:boolean(), true)
		}
	      }
	    };
	_->
	    {ok, Req, LQS}
    end.

%%------------------------------------------------------------
%% function : 'StopTimeSupported'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'StopTimeSupported'(Req, _Type, _Curr, _, _, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetStopTimeSupported(LQS)} of
	{Val, Val} ->
	    ok;
	{Val, _} when Val =/= true, Val =/= false ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:boolean(), false), 
		 high_val=any:create(orber_tc:boolean(), true)
		}
	      }
	    };
	_->
	    {ok, Req, LQS}
    end.

%%------------------------------------------------------------
%% function : 'Timeout'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'Timeout'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetTimeout(LQS)} of
	{Val, Val} ->
	    ok;
	{Val, _} when Val >= ?not_MinTimeout, Val =< ?not_MaxTimeout ->
	    {ok, Req, LQS};
	{Val, _} when is_integer(Val) ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinTimeout), 
		 high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxTimeout)
		}
	      }
	    };
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end.

%%------------------------------------------------------------
%% function : 'OrderPolicy'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'OrderPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetOrderPolicy(LQS), 'CosNotification':'AnyOrder'(),
	  'CosNotification':'PriorityOrder'()} of
	{Val, Val,_,_} ->
	    ok;
	{Val, _, L, H} when Val >= L, Val =< H ->
	    {ok, Req, LQS};
	{Val, _, L, H} when is_integer(Val) ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:short(), L), 
		 high_val=any:create(orber_tc:short(), H)
		}
	      }
	    };
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end.


%%------------------------------------------------------------
%% function : 'DiscardPolicy'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'DiscardPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetDiscardPolicy(LQS), ?not_AnyOrder, ?not_PriorityOrder} of
	{Val, Val,_,_} ->
	    ok;
	{Val, _, L, H} when Val >= L, Val =< H ->
	    {ok, Req, LQS};
	{Val, _, L, H} when is_integer(Val) ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:short(), L), 
		 high_val=any:create(orber_tc:short(), H)
		}
	      }
	    };
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end.

%%------------------------------------------------------------
%% function : 'DiscardPolicy'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'MaximumBatchSize'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetMaximumBatchSize(LQS)} of
	{Val, Val} ->
	    ok;
	{Val, _} when Val >= ?not_MinBatchSize, Val =< ?not_MaxBatchSize ->
	    {ok, Req, LQS};
	{Val, _} when is_integer(Val) ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinBatchSize), 
		 high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxBatchSize)
		}
	      }
	    };
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'UNSUPPORTED_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:long(), ?not_MinBatchSize), 
		 high_val=any:create(orber_tc:long(), ?not_MaxBatchSize)
		}
	      }
	    }
    end.

%%------------------------------------------------------------
%% function : 'PacingInterval'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Comment  : PacingInterval is defined to be:
%%            * TimeBase::UtcT (p 57, 2.5.5, OMG TC Document telecom/98-11-01)
%%            * TimeBase::TimeT (p 189, appendix B, OMG TC Document telecom/98-11-01)
%%            This implementation use TimeBase::TimeT, especially since
%%            TimeBase::UtcT contains information which are of no importance.
%%            When writing this, the OMG homepage contained no information
%%            regarding this.
%%------------------------------------------------------------
'PacingInterval'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetPacingInterval(LQS)} of
	{Val, Val} ->
	    ok;
	{Val, _} when Val >= ?not_MinPacing, Val =< ?not_MaxPacing ->
	    {ok, Req, LQS};
	{Val, _} when is_integer(Val) ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinPacing), 
		 high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxPacing)
		}
	      }
	    };
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_TYPE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end.

%%------------------------------------------------------------
%% function : 'MaxEventsPerConsumer'/6
%% Arguments: Req    - Requested QoS, #'CosNotification_Property'{}
%%            Type   - Requestee, channel | admin | proxy
%%            Curr   - Current QoS, #'CosNotification_Property'{}
%%            Parent - false | ObjRef
%%            Childs - false | [ObjRef1, .., ObjRefN]
%%            LQS    - #qos{} defined in CosNotification_Definitions.hrl
%% Returns  : 
%% Effect   : 
%%------------------------------------------------------------
'MaxEventsPerConsumer'(Req, _Type, _Curr, _Parent, _Childs, LQS) ->
    case {any:get_value(Req#'CosNotification_Property'.value),
	  ?not_GetMaxEventsPerConsumer(LQS)} of
	{Val, Val} ->
	    ok;
	{Val, _} when is_integer(Val) andalso
		      Val >= ?not_MinConsumerEvents andalso
		      Val =< ?not_MaxConsumerEvents ->
	    {ok, Req, LQS};
	{Val, _} when is_integer(Val) ->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'BAD_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinConsumerEvents), 
		 high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxConsumerEvents)
		}
	      }
	    };
	_->
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'UNSUPPORTED_VALUE', 
	       name = Req#'CosNotification_Property'.name,
	       available_range = 
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:long(), ?not_MinConsumerEvents), 
		 high_val=any:create(orber_tc:long(), ?not_MaxConsumerEvents)
		}
	      }
	    }
    end.

%%------------------------------------------------------------
%% function : validate_qos/5
%% Arguments: Wanted  - requested QoS to be set.
%%            Curr    - current QoS OMG style and LQS, local 
%%                      representation of QoS, grouped as {OMGQ, LQS}
%%            Type    - channel | admin | proxy
%%            Parent  - Factory if Channel, Channel if Admin etc
%%            Childs  - Admins if Channel etc
%% Returns  : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{}
%%            case 1 if all supported, case 2 if at least 1 QoS not
%%            supported.
%% See also p59, 2.5.6.4, OMG TC Document telecom/98-11-01. Quote:
%% "If the supplied QoS is supported, it returns additional QoS
%%  properties which could be optionally added as well."
%%------------------------------------------------------------
validate_qos(Wanted, Curr, Type, Parent, Childs) ->
    %% If not supported this function will raise an exception, which we should
    %% not catch, but all we need to is to raise the exception as it is.
    {_, LQS}=set_qos(Wanted, Curr, Type, Parent, Childs),
    NewNPR = check_limits(LQS, ?not_QOS_LIMITS),
    remove_qos(Wanted, LQS, NewNPR).

remove_qos([], _, NPR) ->
    NPR;
remove_qos([H|T], LQS, NPR) ->
    NewNPR=remove(NPR, H#'CosNotification_Property'.name),
    remove_qos(T, LQS, NewNPR).

check_limits(LQS, NPR) ->
    case {?not_GetEventReliability(LQS), ?not_GetConnectionReliability(LQS), 
	  ?not_Persistent, ?not_BestEffort} of
	{P,P,P,_B} ->
	    New = #'CosNotification_NamedPropertyRange'
	      {name=?not_EventReliability,
	       range=
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:short(), ?not_BestEffort), 
		 high_val=any:create(orber_tc:short(), ?not_BestEffort)
		}},
	    NewNPR=change(NPR, ?not_EventReliability, New),
	    remove(NewNPR, ?not_ConnectionReliability);
	{_,B,_P,B} ->
	    remove(NPR, ?not_EventReliability);
	{B,P,P,B} ->
	    New = #'CosNotification_NamedPropertyRange'
	      {name=?not_ConnectionReliability,
	       range=
	       #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:short(), ?not_BestEffort), 
		 high_val=any:create(orber_tc:short(), ?not_BestEffort)
		}},
	    change(NPR, ?not_ConnectionReliability, New)
    end.

%%------------------------------------------------------------
%% function : validate_event_qos/2
%% Arguments: Wanted  - requested QoS to be set.
%%            Curr    - LQS, local representation of QoS
%% Returns  : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{}
%%            case 1 if all supported, case 2 if at least 1 QoS not
%%            supported.
%%------------------------------------------------------------
validate_event_qos(Wanted, Curr) ->
    case v_e_q_helper(Wanted, Curr, []) of
	ok ->
	    [];
	{error, Unsupp} ->
	    corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp})
    end.

v_e_q_helper([], _Curr, []) ->
    %% Parsed all and found no conflicts.
    ok;
v_e_q_helper([], _Curr, Unsupp) ->
    %% Not possible to use these requested QoS.
    {error, Unsupp};

%%--- EventReliability ---%%
v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability, 
					  value=#any{value=?not_BestEffort}}|T], Curr, Unsupp) ->
    %% Always ok.
    v_e_q_helper(T, Curr, Unsupp);
v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability, 
					  value=#any{value=?not_Persistent}}|T], Curr, Unsupp) 
  when ?not_GetConnectionReliability(Curr) =/= ?not_BestEffort,
       ?not_GetEventReliability(Curr) =/= ?not_BestEffort,
       ?not_GetStopTimeSupported(Curr) =/= true ->
    v_e_q_helper(T, Curr, Unsupp);
v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability}|T], 
	     Curr, Unsupp) ->
    %% Impossible to set to Persistent if the connection reliability is best effort.
    v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
			   {code = 'UNAVAILABLE_VALUE', name = ?not_EventReliability,
			    available_range = 
			    #'CosNotification_PropertyRange'{
			      low_val=any:create(orber_tc:null(), null), 
			      high_val=any:create(orber_tc:null(), null)}}|Unsupp]);

%%--- Priority ---%%
v_e_q_helper([#'CosNotification_Property'{name=?not_Priority, value=#any{value=V}}|T], Curr, 
	     Unsupp) ->
    if 
	?not_GetOrderPolicy(Curr) =/= ?not_AnyOrder,
	?not_GetOrderPolicy(Curr) =/= ?not_Priority,
	?not_GetDiscardPolicy(Curr) =/= ?not_Priority ->
	    %% No use setting Priority since it's not currently used.
	    v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
				   {code = 'UNAVAILABLE_VALUE', name = ?not_Priority,
				    available_range = #'CosNotification_PropertyRange'{
				      low_val=any:create(orber_tc:null(), null), 
				      high_val=any:create(orber_tc:null(), null)
				     }}|Unsupp]);
	V =< ?not_HighestPriority, V >= ?not_LowestPriority ->
	    v_e_q_helper(T, Curr, Unsupp);
	true ->
	    v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
				   {code = 'BAD_VALUE', name = ?not_Priority,
				    available_range = 
				    #'CosNotification_PropertyRange'{
				      low_val=any:create(orber_tc:short(), 
							 ?not_LowestPriority), 
				      high_val=any:create(orber_tc:short(), 
							  ?not_HighestPriority)}}|Unsupp])
    end;

%%--- StartTime ---%%
v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp) 
  when ?not_GetStartTimeSupported(Curr) =/= false,
       ?not_GetEventReliability(Curr) =/= ?not_Persistent ->
    v_e_q_helper(T, Curr, Unsupp);
v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp) ->
    v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
			   {code = 'UNAVAILABLE_VALUE', name = ?not_StartTime,
			    available_range = #'CosNotification_PropertyRange'{
			      low_val=any:create(orber_tc:null(), null), 
			      high_val=any:create(orber_tc:null(), null)
			     }}|Unsupp]);

%%--- StopTime ---%%
v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp)
  when ?not_GetStopTimeSupported(Curr) =/= false,
       ?not_GetEventReliability(Curr) =/= ?not_Persistent ->
    v_e_q_helper(T, Curr, Unsupp);
v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp) ->
    v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
			   {code = 'UNAVAILABLE_VALUE', name = ?not_StopTime,
			    available_range = #'CosNotification_PropertyRange'{
			      low_val=any:create(orber_tc:null(), null), 
			      high_val=any:create(orber_tc:null(), null)
			     }}|Unsupp]);

%%--- Timeout ---%%
v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp)
  when  ?not_GetStopTimeSupported(Curr) =/= false,
	?not_GetEventReliability(Curr) =/= ?not_Persistent ->
    v_e_q_helper(T, Curr, Unsupp);
v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp) ->
    v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
			   {code = 'UNAVAILABLE_VALUE', name = ?not_Timeout,
			    available_range = #'CosNotification_PropertyRange'{
			      low_val=any:create(orber_tc:null(), null), 
			      high_val=any:create(orber_tc:null(), null)
			     }}|Unsupp]);

%%--- Unknown Event QoS ---%%
v_e_q_helper([#'CosNotification_Property'{name=Name}|T], Curr, Unsupp) ->
    %% Unsupported property.
    v_e_q_helper(T, Curr, [#'CosNotification_PropertyError'
			   {code = 'BAD_PROPERTY', name = Name,
			    available_range = #'CosNotification_PropertyRange'{
			      low_val=any:create(orber_tc:null(), null), 
			      high_val=any:create(orber_tc:null(), null)
			     }}|Unsupp]);
v_e_q_helper(What, _, _) ->
    %% Not a Property struct.
    orber:dbg("[~p] CosNotification_Common:v_e_q_helper(~p);~n"
	      "Not a CosNotification_Property struct.", 
	      [?LINE, What], ?DEBUG_LEVEL),
    corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).

%%-------------- QOS HELP FUNCTIONS --------------------------
%%------------------------------------------------------------
%% function : set_properties/9
%% Arguments: Wanted  - requested QoS to be set.
%%            Current - current QoS OMG style
%%            Type    - channel | admin | proxy
%%            Supported - List of supported QoS
%%            Unsupp  - acc
%%            NewQoS  - acc
%%            Parent  - Factory if Channel, Channel if Admin etc
%%            Childs  - Admins if Channel etc
%%            LQS     - local representation of QoS.
%% Returns  : {NewOMGStyleQoS, NewLocalQoS} | #'CosNotification_UnsupportedQoS'{}
%%------------------------------------------------------------
set_properties(Wanted, Current, Type, Supported, Unsupp, NewQoS, Parent, Childs, LQS) ->
    case do_set_properties(Wanted, Current, Type, Supported, Unsupp, NewQoS, Parent, Childs, LQS) of
	{error, Exc} ->
	     corba:raise(Exc);
	Result ->
	    Result
    end.

do_set_properties([], Curr, channelAdm, _, [], NewQoS,_,_,LAS) ->
    merge_properties(NewQoS, Curr, LAS);
do_set_properties([], Curr, _, _, [], NewQoS,_,_,LQS) ->
    %% set_local_qos and merge_properties are help functions found at the end of QoS
    %% functions.
    NewLQS = set_local_qos(NewQoS, LQS),
    merge_properties(NewQoS, Curr, NewLQS);
do_set_properties([], _, channelAdm, _, Unsupp, _,_,_,_) ->
    {error, #'CosNotification_UnsupportedAdmin'{admin_err = Unsupp}};
do_set_properties([], _, _, _, Unsupp, _,_,_,_) ->
    {error, #'CosNotification_UnsupportedQoS'{qos_err = Unsupp}};

do_set_properties([Req|Tail], Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) ->
    %% set_values and is_supported are help functions found at the end of QoS
    %% functions.
    case set_values(is_supported(Supported, Req), Req, Type, Curr, Parent, Childs,LQS) of
	{unsupported, U} ->
	    do_set_properties(Tail, Curr, Type, Supported, [U|Unsupp], NewQoS, Parent, Childs,LQS);
	{ok, S, NewLQS} ->
	    do_set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,NewLQS);
	{ok, S} ->
	    do_set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,LQS);
	ok ->
	    do_set_properties(Tail, Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS)
    end.
    

set_values(unsupported,Req,_,_,_,_,_) ->
    {unsupported, 
     #'CosNotification_PropertyError'{
       code = 'BAD_PROPERTY', 
       name = Req#'CosNotification_Property'.name,
       available_range = #'CosNotification_PropertyRange'{
	 low_val=any:create(orber_tc:null(), null), 
	 high_val=any:create(orber_tc:null(), null)
	}
      }
    };
set_values({ok, Func}, Req, Type, Curr, Parent, Childs, LQS) ->
    ?MODULE:Func(Req, Type, Curr, Parent, Childs, LQS).

%% Update OMG style QoS list with new values.
merge_properties([], NewCurrQoS, LQS) ->
    {NewCurrQoS, LQS}; 
merge_properties([H|T], Curr, LQS) ->
    merge_properties(T, lists:keyreplace(H#'CosNotification_Property'.name, %% get key.
					 #'CosNotification_Property'.name, %% get index.
					 Curr, H), LQS).

%% Is the Property S among our supported QoS?    
is_supported([], _) -> 
    unsupported;
is_supported([{Name, Func}|_], #'CosNotification_Property'{name=Name}) -> 
    {ok, Func};
is_supported([_|T], S) -> 
    is_supported(T, S).

%% Find matching S-Property from a list of OMG style QoS
extract([], _) -> unsupported;
extract([H|_T], S) when H#'CosNotification_Property'.name==
		       S#'CosNotification_Property'.name -> 
    {ok, H};
extract([_|T], S) -> extract(T,S).

%% Find matching Property name from a list of OMG style QoS
extract_value([], _) -> unsupported;
extract_value([H|_T], Key) when H#'CosNotification_Property'.name== Key ->
    {ok, any:get_value(H#'CosNotification_Property'.value)};
extract_value([_|T], Key) -> extract(T,Key).

%% Remove matching S-QoS from a list of OMG style QoS
remove(List, Key) -> 
    lists:keydelete(Key,
		    #'CosNotification_NamedPropertyRange'.name, %% get index.
		    List).

change(List, Key, New) ->
    lists:keyreplace(Key,
		     #'CosNotification_NamedPropertyRange'.name, %% get index.
		     List, New).
%% Get QoS from supplied objects and check if it's the same as S.
check_with_relatives([], S, LQS) ->
    {ok, S, LQS};
check_with_relatives([undefined|T], S, LQS) ->
    check_with_relatives(T, S, LQS);
check_with_relatives([H|T], S, LQS) ->
    case catch extract('CosNotification_QoSAdmin':get_qos(H), S) of
	{ok, S} ->
	    check_with_relatives(T, S, LQS);
	_->
	    %% Varioues reasons for this case (Object not responding, not supported)
	    {unsupported, 
	     #'CosNotification_PropertyError'{
	       code = 'UNAVAILABLE_PROPERTY', 
	       name = S#'CosNotification_Property'.name,
	       available_range = #'CosNotification_PropertyRange'{
		 low_val=any:create(orber_tc:null(), null), 
		 high_val=any:create(orber_tc:null(), null)
		}
	      }
	    }
    end.

%% Set new values to locally defined representation of QoS. Using this approach is 
%% necessary since we must state the record-field at compile-time.
set_local_qos([], LQS) -> LQS;
set_local_qos([#'CosNotification_Property'{name=N,value=V}|T], LQS) ->
    NewLQS = 
	case N of
	    "EventReliability" ->
		?not_SetEventReliability(LQS, any:get_value(V));  
	    "ConnectionReliability" ->
		?not_SetConnectionReliability(LQS, any:get_value(V));
	    "Priority" ->
		?not_SetPriority(LQS, any:get_value(V));
	    "Timeout" ->
		?not_SetTimeout(LQS, any:get_value(V));
	    "OrderPolicy" ->
		?not_SetOrderPolicy(LQS, any:get_value(V));
	    "DiscardPolicy" ->
		?not_SetDiscardPolicy(LQS, any:get_value(V));
	    "MaximumBatchSize" ->
		?not_SetMaximumBatchSize(LQS, any:get_value(V));
	    "PacingInterval" ->
		?not_SetPacingInterval(LQS, any:get_value(V));
	    "StartTimeSupported" ->
		?not_SetStartTimeSupported(LQS, any:get_value(V));
	    "StopTimeSupported" ->
		?not_SetStopTimeSupported(LQS, any:get_value(V));
	    "MaxEventsPerConsumer" ->
		?not_SetMaxEventsPerConsumer(LQS, any:get_value(V))
	end,
    set_local_qos(T, NewLQS).

%%%%%%%%%%%%%%%%% END QOS FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%

%%--------------- END OF MODULE ------------------------------
