-module(base,[ID,PID]).
-compile(export_all).
-define(timeout,1000).

%% Starting an instance with a single argument looks the id up in the
%% database, pulls any old data, and creates an instance.  At this
%% point the instance sets its prototype to 'SELF', and finally
%% returns.

new(Id) ->
    Pid = basedb:start_base(Id),
    Inst = instance(Id,Pid),
    Inst:proto('SELF'),
    Inst.

%% Whereas with two arguments (both strings), the instance returned
%% will have a reference to the prototype identified by Proto.

new(Id,Proto) ->
    Pid = basedb:start_base(Id),
    Inst = instance(Id,Pid),
    Inst:proto(Proto),
    Inst.

id() -> ID.

proto(ProtoId) -> tell({proto,ProtoId}).

proto() -> look(proto).

data() -> look(data).

data(NewData) -> ask({data,NewData}).

attributes() -> look(attributes).

select(AttList) -> look({select,AttList}).

sync_insert(KVList) -> ask({insert,KVList}).

insert(KVList) -> tell({insert,KVList}).    

%% COMMUNICATION FUCNCTIONS.

%% look/1 never alters the internal state, and expects a reply

look(Req) ->
    Ref = make_ref(),
    PID ! {look,Req,Ref,self()},
    receive
	{Ref,Reply} -> Reply
    after ?timeout ->
	    {error,timeout}
    end.

%% ask may or may not allter the interal state, and it also expects a
%% reply

ask(Req) ->
    Ref = make_ref(),
    PID ! {ask,Req,Ref,self()},
    receive
	{Ref,Reply} -> Reply
    after ?timeout ->
	    {error,timeout}	
    end.

%% tell doesn't expect a reply.

tell(Req) ->
    PID ! {tell,Req},
    ok.
	    
